Most Next.js tutorials show you how to start a project.
None of them show you how to organize one that won't fall apart at scale.
Here's the exact structure I'm using for Softchic — a template
marketplace I'm currently building — and the reasoning behind every folder.
The Full Structure
src/
├── app/
│ ├── (auth)/
│ │ ├── login/
│ │ │ └── page.tsx
│ │ └── register/
│ │ └── page.tsx
│ ├── (main)/
│ │ ├── browse/
│ │ │ └── page.tsx
│ │ └── templates/
│ │ └── [slug]/
│ │ └── page.tsx
│ ├── layout.tsx
│ ├── page.tsx
│ └── globals.css
├── components/
│ ├── ui/
│ ├── shared/
│ │ ├── Navbar.tsx
│ │ └── Footer.tsx
│ └── sections/
│ ├── Hero.tsx
│ └── BrowseSection.tsx
├── lib/
│ └── utils.ts
├── hooks/
├── types/
└── config/
└── site.ts
Why This Structure
app/ with Route Groups
Route groups (folders wrapped in parentheses like (auth) and (main))
let you organize pages without affecting the URL.
/app/(auth)/login/page.tsx still resolves to /login in the browser —
the (auth) folder is invisible to the router.
This keeps related pages grouped without polluting your URLs.
components/ui/
This is where shadcn/ui drops its components when you run:
npx shadcn@latest add button
Never manually edit these — treat them as a local library.
components/shared/
Global components used across multiple pages — Navbar, Footer,
modals that appear everywhere. If it's reused on more than two pages,
it lives here.
components/sections/
Page-specific sections like Hero.tsx or BrowseSection.tsx.
These are too large to live inside a page file but too specific
to be "shared." This folder keeps your page.tsx files clean.
lib/utils.ts
Utility functions — shadcn auto-generates a cn() helper here for
merging Tailwind classes. Add your own helpers here too.
hooks/
Custom React hooks. As your app grows, logic like useCart(),
useCurrency(), or useAuth() belongs here — not inside components.
types/
All your TypeScript interfaces and types in one place.
When your Template type is used in 6 different files,
you define it once here and import it everywhere.
config/site.ts
Site-wide constants — your app name, description, social links,
base URL. One file to update when things change.
export const siteConfig = {
name: "Softchic",
description: "Premium website templates for developers and businesses.",
url: "#",
links: {
twitter: "https://x.com/ifehdelight",
},
}
The Rule I Follow
If a file is used in more than two places — it gets its own home.
If a component is longer than 150 lines — it gets broken up.
That's it. Simple rules prevent messy codebases.
What's Next
This is the foundation Softchic is being built on.
Next post I'm breaking down how Tailwind CSS v4 changes
the way you write styles — and what actually surprised me.
The Softchic waitlist drops soon — follow me here on Dev.to
so you don't miss it.
— Delight | Founder, Softchic
@ifehdelight on X
Top comments (1)
The
(auth)/(main)route groups do real work here: they preserve a clean URL shape while still giving the team a map of the product areas. I also like drawing a hard line betweencomponents/uias the shadcn-owned layer andcomponents/sectionsfor things likeHero.tsxandBrowseSection.tsx. The founder/engineer tradeoff I'd watch is when Softchic grows from pages into workflows; at that point, colocating template, checkout, and account logic by feature can matter more than keeping every hook or type in one global folder.