There's a version of this post that reads like a marketing brochure. I'm not writing that version.
We used Claude Code on a real production project — a Next.js 15 headless storefront for an ecommerce client, built on the Shopify Storefront API with TypeScript, Tailwind CSS, shadcn/ui components, and Directus as the CMS layer. Over 60 components. Multiple API integrations. A codebase that had to ship.
This is what we actually learned.
The Project: What We Were Working With
The stack was deliberate:
- Next.js 15 with App Router and React Server Components
- Shopify Storefront API for product data, cart, and checkout
- TypeScript throughout — strict mode, no escape hatches
- Tailwind CSS + shadcn/ui for the component layer
- Directus as a headless CMS for editorial content
- Custom checkout extensions and post-purchase flows
This isn't a toy app. The client needed performance, reliability, and a codebase that their in-house team could maintain. That last constraint matters a lot when you're deciding how much to let an AI agent loose on shared code.
Setup: The Work Before the Work
The single most important thing we did before writing a line of code with Claude Code was invest serious time in CLAUDE.md.
This file is Claude Code's context layer — it's the first thing it reads in any session, and it shapes every decision the model makes about your codebase. We treated it like onboarding documentation for a senior hire who needs to be productive on day one.
Our CLAUDE.md for this project included:
# Project: [Client] Storefront
## Tech Stack
- Next.js 15 (App Router, RSC-first)
- TypeScript strict mode
- Tailwind CSS + shadcn/ui
- Shopify Storefront API v2024-04
- Directus 11 (headless CMS)
## Folder Structure
- /app — Next.js App Router pages and layouts
- /components/ui — shadcn/ui base components (do not modify directly)
- /components/storefront — custom storefront components
- /lib/shopify — Storefront API client and typed queries
- /lib/directus — CMS client and typed queries
## Key Commands
- npm run dev — local development (port 3000)
- npm run type-check — TypeScript validation only
- npm run lint — ESLint
- npm test — Jest + React Testing Library
## Code Standards
- All components use TypeScript interfaces, not `any`
- Server Components by default; add 'use client' only when needed
- Fetch calls go in /lib, not inside components
- shadcn/ui components live in /components/ui — extend, don't modify
## Workflow Rules
- Always run type-check after changes
- New components need a .test.tsx file
- Cart state is managed via CartProvider — touch with caution
This setup investment paid back within the first session. Claude Code understood our conventions, suggested Server Components correctly, and stopped trying to put fetch calls inside React components.
If you skip CLAUDE.md, you're going to spend half your time correcting convention violations instead of shipping features.
What Claude Code Was Genuinely Excellent At
React Server Components and data fetching patterns. This was the biggest win. Claude Code understood the App Router's RSC model well — it defaulted to async Server Components for data-heavy pages, knew when to reach for Suspense boundaries, and wrote clean generateMetadata functions without prompting.
// Example: Claude Code generated this without any correction needed
export async function generateMetadata(
{ params }: { params: { handle: string } }
): Promise<Metadata> {
const product = await getProduct(params.handle);
if (!product) return { title: 'Product Not Found' };
return {
title: product.seo?.title || product.title,
description: product.seo?.description || product.description,
openGraph: {
images: product.featuredImage ? [product.featuredImage.url] : []
}
};
}
shadcn/ui integration. Because shadcn/ui components are installed directly into the project (not imported from a package), Claude Code could read the actual component source and extend it correctly. It never tried to override styles in ways that would break the component contract. When we asked it to build a custom ProductCard that used the base Card component, it did it right the first time.
API route handlers and typed Shopify queries. Our /lib/shopify layer uses GraphQL fragments and typed responses. Claude Code learned the pattern from existing files and replicated it consistently for new queries — typed, with proper error handling, matching our existing structure.
Test coverage. This was unexpected. When we established the rule that new components needed .test.tsx files, Claude Code started writing them without being asked. Not perfect tests, but solid coverage of expected renders and user interactions. Over the project's duration, our coverage improved naturally rather than as a bolted-on cleanup task.
The Directus MCP Integration
We connected Claude Code to the Directus MCP server mid-project, and it removed an entire class of frustration.
Before the integration, working with Directus content required context-switching: checking the CMS admin for field names, copying schema details into the chat, hoping nothing was out of date. Claude Code would occasionally generate field names that were subtly wrong (hero_text vs hero_heading), and catching those errors cost time.
After connecting the MCP server, Claude Code could query the actual Directus schema directly. It knew the exact field names, understood the relational structure, and generated correctly typed fetch calls on the first attempt.
The practical impact: what used to take 20–30 minutes of back-and-forth (write query → find field name error → correct → retest) took 5 minutes. For a project with significant CMS-driven content, that compounds fast.
What Went Wrong: The Cart Cascade Incident
This is the most important section of this post.
About three weeks into the project, I asked Claude Code to add a loading state to the cart button component — what seemed like a simple, isolated change. I had Auto-Accept enabled and wasn't paying close attention.
The change cascaded.
Our CartButton component shared state through CartProvider. Modifying the component's internal state handling created a type mismatch in the CartProvider interface. That broke two other components consuming cart state — CartDrawer and MiniCart — neither of which was obviously connected to CartButton from a surface-level reading.
The TypeScript errors were caught quickly (strict mode earned its reputation), but the lesson stuck: Auto-Accept is dangerous on shared components. Full stop.
We changed our workflow after this:
- Auto-Accept stays off during working hours
- For any component in
/components/storefrontthat's consumed by more than one other component, we now use Plan Mode first (Shift+Tab in Claude Code) - Plan Mode surfaces the dependency chain before a single line changes
Had I used Plan Mode for the cart change, Claude Code would have identified the CartProvider interface dependency upfront. The cascade wouldn't have happened.
Shared state management, global providers, and utility functions that get called in multiple places — these are the zones where Plan Mode is non-negotiable.
The Context Drift Problem
Claude Code's 200K context window sounds enormous until you're three hours into a complex session and start noticing the responses getting subtly worse. Earlier decisions aren't being referenced. Code that should follow established patterns starts drifting.
This isn't a failure of the tool — it's a constraint you need to plan around.
Our solution: a SESSION_NOTES.md file that we update at natural breakpoints.
## Session: Product Page Work [2026-02-14]
### Completed
- Built ProductGallery with zoom functionality
- Added variant selector with out-of-stock states
### Active Context
- Working on: add-to-cart flow
- CartProvider uses optimistic updates — don't change the mutation signature
- ProductPage fetches variant data server-side; don't move to client
### Known Constraints
- Shopify checkout webhook requires exact price format (cents, integer)
- Directus 'products' collection uses 'shopify_handle' not 'slug'
At the start of a new session — or when I sense drift after a long one — I paste the session notes into the conversation. Context restored. Consistency maintained.
For long-running projects, this file becomes one of the most valuable things in the repo.
Velocity: The Honest Numbers
We don't make up metrics here. As a Shopify Partner, we've built enough storefronts to know what "normal" velocity looks like for a team of our size.
For this project:
- Routine component builds (non-shared, clear spec): 50–60% faster compared to pure manual development
- API integration work (typed queries, error handling, loading states): 40–50% faster
- Complex shared state work (cart, auth, global providers): roughly the same — the planning overhead with Claude Code matched the time saved on implementation
- Test writing: what used to be a cleanup task at project end happened continuously, at no meaningful time cost
The 50–60% figure is real but requires two conditions: a well-configured CLAUDE.md and clean session hygiene. Without those, the gains shrink to 20–30% — still positive, but not transformative.
How We Think About It Now
The mental model that helped us most: Claude Code is a skilled contractor who is brilliant but has no long-term memory and no intuition for your political landmines.
A skilled contractor needs a proper brief. They need to know the conventions, the constraints, the parts of the codebase that are sensitive. Given that context, they produce excellent work quickly. Without it, they make reasonable decisions that don't fit your specific situation.
The investment in setup — CLAUDE.md, session notes, clear folder conventions, strict TypeScript — is the brief. It's not overhead. It's the reason the contractor performs.
We also found that Claude Code's presence improved our own practices. Because we had to articulate our conventions clearly enough for an AI to follow them, we had to actually have clear conventions. The codebases we used Claude Code on ended up better documented and more consistent than the ones we didn't.
The DPIIT Angle
As a DPIIT-recognised startup, part of our mandate is building with modern tooling and demonstrating what's possible for Indian product teams. AI-augmented development workflows are where that rubber meets road. We're not just using these tools for speed — we're using them to demonstrate that a 12-person team in Kolkata can build production-grade headless commerce infrastructure that competes with agencies three times our size.
If you're building on Next.js and want to talk about the workflow in detail, our AI automation services page covers how we integrate these tools into client delivery.
FAQ
Does Claude Code handle TypeScript errors well?
Yes, especially in Plan Mode. It reads your tsconfig.json and existing types, and tends to generate type-safe code when given proper context. Where it struggles is with complex generic types or third-party library type definitions it hasn't seen before — in those cases, it'll sometimes produce technically valid but overly verbose type annotations. Still easier to simplify than to write from scratch.
We use both Shopify Liquid and Next.js — can Claude Code handle a mixed codebase?
It can, but you need to be explicit in CLAUDE.md about which parts of the codebase are Liquid vs. Next.js. Without that, it will sometimes suggest React patterns for Liquid templates and vice versa. Once you've established the boundary, it respects it consistently.
How long does the initial CLAUDE.md setup take?
For a mid-size project (50+ components), plan 2–4 hours to write a genuinely useful CLAUDE.md. That sounds like a lot, but you'll recover it within the first week of active development. For smaller projects, 30–60 minutes is usually enough.
Can we use Claude Code for code review, not just generation? Absolutely — and it's genuinely useful in this role. We use it to audit PR diffs for convention violations, identify missing error handling, and spot places where Server Components were unnecessarily converted to Client Components. It's not a replacement for human review, but it catches a meaningful percentage of issues before review even starts.
What about performance-sensitive code paths?
Be explicit. Claude Code doesn't automatically optimise for Web Vitals or Core Web Vitals unless you tell it to. We added a section to CLAUDE.md stating that above-the-fold components must avoid layout shift and that images use next/image with explicit dimensions. Once that was in the brief, it followed consistently.
Is Claude Code suitable for junior developers to use? With guardrails, yes. With Auto-Accept and no code review, no. Junior developers benefit most when they use Claude Code to understand patterns — read what it generates, understand why it made those choices, then accept or modify. Using it as a "just make it work" shortcut tends to produce code that works today but causes confusion later.
How do you handle context drift in very long sessions?
The SESSION_NOTES.md approach described above, plus a hard rule: if a session has been running for more than 2–3 hours, start a fresh one. The time cost of re-establishing context is lower than the cost of debugging decisions made from a drifted context window.
Does this workflow scale to a full dev team?
Yes, but it requires discipline. The CLAUDE.md file should be committed to the repo and treated as living documentation. Teams need to agree upfront that Claude Code follows the conventions defined there — not each developer's personal preferences. When that alignment exists, the consistency gains compound across the team. When it doesn't, you get a codebase with four different patterns for the same thing.
Rishabh Sethia is the Founder & CEO of Innovatrix Infotech, a DPIIT Recognised Startup and Shopify Partner based in Kolkata. Former Senior Software Engineer and Head of Engineering. He writes about engineering decisions, AI-augmented development, and building product teams that ship.