├── src
├── modules
│ └── home
│ │ ├── index.ts
│ │ ├── Home.module.css
│ │ └── Home.tsx
├── common
│ ├── components
│ │ └── marketing
│ │ │ ├── Card
│ │ │ ├── index.ts
│ │ │ ├── Card.tsx
│ │ │ └── Card.module.css
│ │ │ ├── Footer
│ │ │ ├── index.ts
│ │ │ ├── Footer.module.css
│ │ │ └── Footer.tsx
│ │ │ └── SimpleGrid
│ │ │ ├── index.ts
│ │ │ ├── SimpleGrid.tsx
│ │ │ └── SimpleGrid.module.css
│ └── styles
│ │ └── globals.css
└── pages
│ ├── _app.tsx
│ ├── api
│ └── hello.ts
│ └── index.tsx
├── .eslintrc.json
├── next.config.js
├── public
├── favicon.ico
└── vercel.svg
├── next-env.d.ts
├── README.md
├── package.json
├── .gitignore
└── tsconfig.json
/src/modules/home/index.ts:
--------------------------------------------------------------------------------
1 | export { Home } from "./Home";
2 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/src/common/components/marketing/Card/index.ts:
--------------------------------------------------------------------------------
1 | export { Card } from "./Card";
2 |
--------------------------------------------------------------------------------
/src/common/components/marketing/Footer/index.ts:
--------------------------------------------------------------------------------
1 | export { Footer } from "./Footer";
2 |
--------------------------------------------------------------------------------
/src/common/components/marketing/SimpleGrid/index.ts:
--------------------------------------------------------------------------------
1 | export { SimpleGrid } from "./SimpleGrid";
2 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | module.exports = {
3 | reactStrictMode: true,
4 | }
5 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okeeffed/nextjs-enterprise-project-structure/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import "@styles/globals.css";
2 | import type { AppProps } from "next/app";
3 |
4 | function MyApp({ Component, pageProps }: AppProps) {
5 | return ;
6 | }
7 |
8 | export default MyApp;
9 |
--------------------------------------------------------------------------------
/src/common/components/marketing/SimpleGrid/SimpleGrid.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import styles from "./SimpleGrid.module.css";
3 |
4 | export const SimpleGrid: React.FC = ({ children }) => {
5 | return
{children}
;
6 | };
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Next.js Enterprise Project Structure
2 |
3 | This repo goes along with the [blog post on my website](https://blog.dennisokeeffe.com/blog/2021-12-06-nextjs-enterprise-project-structure).
4 |
5 | ## Getting started
6 |
7 | ```s
8 | $ npm run dev
9 | ```
10 |
--------------------------------------------------------------------------------
/src/common/components/marketing/SimpleGrid/SimpleGrid.module.css:
--------------------------------------------------------------------------------
1 | .grid {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | flex-wrap: wrap;
6 | max-width: 800px;
7 | }
8 |
9 | @media (max-width: 600px) {
10 | .grid {
11 | width: 100%;
12 | flex-direction: column;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/common/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
--------------------------------------------------------------------------------
/src/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from 'next'
3 |
4 | type Data = {
5 | name: string
6 | }
7 |
8 | export default function handler(
9 | req: NextApiRequest,
10 | res: NextApiResponse
11 | ) {
12 | res.status(200).json({ name: 'John Doe' })
13 | }
14 |
--------------------------------------------------------------------------------
/src/common/components/marketing/Footer/Footer.module.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | display: flex;
3 | flex: 1;
4 | padding: 2rem 0;
5 | border-top: 1px solid #eaeaea;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .footer a {
11 | display: flex;
12 | justify-content: center;
13 | align-items: center;
14 | flex-grow: 1;
15 | }
16 |
17 | .logo {
18 | height: 1em;
19 | margin-left: 0.5rem;
20 | }
21 |
--------------------------------------------------------------------------------
/src/common/components/marketing/Card/Card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import styles from "./Card.module.css";
3 |
4 | interface CardProps {
5 | href: string;
6 | title: string;
7 | body: string;
8 | }
9 |
10 | export const Card: React.FC = ({ href, title, body }) => {
11 | return (
12 |
13 | {title}
14 | {body}
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-enterprise-project-structure",
3 | "private": true,
4 | "scripts": {
5 | "dev": "next dev",
6 | "build": "next build",
7 | "start": "next start",
8 | "lint": "next lint"
9 | },
10 | "dependencies": {
11 | "next": "12.0.7",
12 | "react": "17.0.2",
13 | "react-dom": "17.0.2"
14 | },
15 | "devDependencies": {
16 | "@types/node": "16.11.11",
17 | "@types/react": "17.0.37",
18 | "eslint": "8.4.0",
19 | "eslint-config-next": "12.0.7",
20 | "typescript": "4.5.2"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
36 | # typescript
37 | *.tsbuildinfo
38 |
--------------------------------------------------------------------------------
/src/common/components/marketing/Card/Card.module.css:
--------------------------------------------------------------------------------
1 | .card {
2 | margin: 1rem;
3 | padding: 1.5rem;
4 | text-align: left;
5 | color: inherit;
6 | text-decoration: none;
7 | border: 1px solid #eaeaea;
8 | border-radius: 10px;
9 | transition: color 0.15s ease, border-color 0.15s ease;
10 | max-width: 300px;
11 | }
12 |
13 | .card:hover,
14 | .card:focus,
15 | .card:active {
16 | color: #0070f3;
17 | border-color: #0070f3;
18 | }
19 |
20 | .card h2 {
21 | margin: 0 0 1rem 0;
22 | font-size: 1.5rem;
23 | }
24 |
25 | .card p {
26 | margin: 0;
27 | font-size: 1.25rem;
28 | line-height: 1.5;
29 | }
30 |
--------------------------------------------------------------------------------
/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import type { NextPage } from "next";
2 | import Head from "next/head";
3 | import { Home } from "@modules/home";
4 | import { Footer } from "@components/marketing/Footer";
5 |
6 | const IndexPage: NextPage = () => {
7 | return (
8 |
13 |
14 |
Create Next App
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 | };
23 |
24 | export default IndexPage;
25 |
--------------------------------------------------------------------------------
/src/common/components/marketing/Footer/Footer.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import Image from "next/image";
3 | import styles from "./Footer.module.css";
4 |
5 | export const Footer: React.FC = () => {
6 | return (
7 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@components/*": ["src/common/components/*"],
6 | "@styles/*": ["src/common/styles/*"],
7 | "@modules/*": ["src/modules/*"]
8 | },
9 | "target": "es5",
10 | "lib": ["dom", "dom.iterable", "esnext"],
11 | "allowJs": true,
12 | "skipLibCheck": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noEmit": true,
16 | "esModuleInterop": true,
17 | "module": "esnext",
18 | "moduleResolution": "node",
19 | "resolveJsonModule": true,
20 | "isolatedModules": true,
21 | "jsx": "preserve",
22 | "incremental": true
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/src/modules/home/Home.module.css:
--------------------------------------------------------------------------------
1 | .main {
2 | min-height: 100vh;
3 | padding: 4rem 0;
4 | flex: 1;
5 | display: flex;
6 | flex-direction: column;
7 | justify-content: center;
8 | align-items: center;
9 | }
10 |
11 | .title a {
12 | color: #0070f3;
13 | text-decoration: none;
14 | }
15 |
16 | .title a:hover,
17 | .title a:focus,
18 | .title a:active {
19 | text-decoration: underline;
20 | }
21 |
22 | .title {
23 | margin: 0;
24 | line-height: 1.15;
25 | font-size: 4rem;
26 | }
27 |
28 | .title,
29 | .description {
30 | text-align: center;
31 | }
32 |
33 | .description {
34 | margin: 4rem 0;
35 | line-height: 1.5;
36 | font-size: 1.5rem;
37 | }
38 |
39 | .code {
40 | background: #fafafa;
41 | border-radius: 5px;
42 | padding: 0.75rem;
43 | font-size: 1.1rem;
44 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
45 | Bitstream Vera Sans Mono, Courier New, monospace;
46 | }
47 |
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/modules/home/Home.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Card } from "@components/marketing/Card";
3 | import { SimpleGrid } from "@components/marketing/SimpleGrid";
4 | import styles from "./Home.module.css";
5 |
6 | export const Home: React.FC = () => {
7 | return (
8 |
9 |
10 | Welcome to Next.js!
11 |
12 |
13 |
14 | Get started by editing{" "}
15 | pages/index.tsx
16 |
17 |
18 |
19 |
24 |
29 |
34 |
39 |
40 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------