├── .github ├── dependabot.yml └── workflows │ └── merge-me.yaml ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── __tests__ └── page.test.tsx ├── app ├── head.tsx ├── layout.tsx └── page.tsx ├── eslint.config.mjs ├── next-env.d.ts ├── next.config.js ├── package.json ├── postcss.config.mjs ├── public ├── favicon.ico ├── vercel-light.svg └── vercel.svg ├── styles └── globals.scss ├── tailwind.config.js ├── tsconfig.json ├── vitest.config.ts └── yarn.lock /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/merge-me.yaml: -------------------------------------------------------------------------------- 1 | name: Merge me! 2 | 3 | on: 4 | check_suite: 5 | types: 6 | - completed 7 | 8 | jobs: 9 | merge-me: 10 | name: Merge me! 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Impersonate update bot 14 | uses: tibdex/github-app-token@v1 15 | id: generate-token 16 | with: 17 | app_id: ${{ secrets.APP_ID }} 18 | private_key: ${{ secrets.APP_KEY }} 19 | - name: Approve and merge! 20 | uses: ridedott/merge-me-action@v2 21 | with: 22 | # Depending on branch protection rules, a manually populated 23 | # `GITHUB_TOKEN_WORKAROUND` secret with permissions to push to 24 | # a protected branch must be used. This secret can have an arbitrary 25 | # name, as an example, this repository uses `DOTTBOTT_TOKEN`. 26 | # 27 | # When using a custom token, it is recommended to leave the following 28 | # comment for other developers to be aware of the reasoning behind it: 29 | # 30 | # This must be used as GitHub Actions token does not support pushing 31 | # to protected branches. 32 | GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} 33 | PRESET: DEPENDABOT_MINOR 34 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn precommit 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .next 2 | node_modules 3 | public 4 | package-lock.json -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 MikevPeeren 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Next.js TypeScript TailwindCSS & Sass Starter 2 | 3 |

4 | License 5 | Next.js Version 6 | React Version 7 | TailwindCSS Version 8 |

9 | 10 | Modern, production-ready starter template for Next.js projects with TypeScript, TailwindCSS v4, and Sass. Includes essential developer tools for code quality and testing. 11 | 12 | ## ✨ Features 13 | 14 | This starter provides: 15 | 16 | - **App Router** - Next.js 15.2 with the latest App Router architecture 17 | - **Modern React** - Uses React 19.1 with latest features and optimizations 18 | - **Type Safety** - Full TypeScript integration with strict type checking 19 | - **Modern Styling** - TailwindCSS v4.0 with Sass support for advanced styling 20 | - **Testing Ready** - Vitest and React Testing Library pre-configured 21 | - **Code Quality** - ESLint, Prettier, Husky, and Lint-Staged for high-quality code 22 | - **Performance Analysis** - Bundle analyzer for optimizing your app's size 23 | - **Developer Experience** - Hot reloading, organized project structure 24 | 25 | ## 🧰 Tech Stack 26 | 27 | - ⚡️ [Next.js 15.2](https://nextjs.org/) - React framework with App Router 28 | - ⚛️ [React 19.1](https://reactjs.org/) - JavaScript library for building user interfaces 29 | - 🧪 [Vitest 3.0](https://vitest.dev/) - Next generation testing framework 30 | - 🧁 [TailwindCSS v4.0](https://tailwindcss.com/) - Utility-first CSS framework 31 | - ✨ [TypeScript 5.8](https://www.typescriptlang.org/) - Strongly typed programming language 32 | - 🎉 [Sass 1.86](https://sass-lang.com/) - Professional grade CSS extension language 33 | - 📏 [ESLint v9.23](https://eslint.org/) - Find and fix problems in JavaScript code 34 | - 🦋 [Prettier 3.5](https://prettier.io/) - Opinionated code formatter 35 | - 🐶 [Husky 9.1](https://github.com/typicode/husky) - Git hooks to improve commits 36 | - 🧹 [Lint Staged 15.5](https://github.com/okonet/lint-staged) - Run linters against staged git files 37 | - 🔎 [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer) - Analyze your project bundles 38 | 39 | ## ⚡️ Quick Start 40 | 41 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/project?template=https://github.com/MikevPeeren/next-typescript-tailwindcss-sass-starter) 42 | 43 | ## 🚀 Getting Started 44 | 45 | Run the following command to create a new project with this Starter: 46 | 47 | ```bash 48 | yarn create next-app my-app -e https://github.com/MikevPeeren/next-typescript-tailwindcss-sass-starter 49 | # or 50 | npx create-next-app my-app -e https://github.com/MikevPeeren/next-typescript-tailwindcss-sass-starter 51 | ``` 52 | 53 | Once the project and dependencies are finished installing, you can navigate to that directory and start up the development server with: 54 | 55 | ```bash 56 | yarn dev 57 | # or 58 | npm run dev 59 | ``` 60 | 61 | Open [http://localhost:3000](http://localhost:3000) with your browser to see your new project! 62 | 63 | ## 📝 Available Scripts 64 | 65 | - `yarn dev` - Starts the development server 66 | - `yarn build` - Builds the app for production 67 | - `yarn start` - Runs the built app in production mode 68 | - `yarn lint` - Runs ESLint for code linting 69 | - `yarn test` - Runs Vitest test suite 70 | - `yarn format` - Runs Prettier to format your code 71 | - `yarn prepare` - Sets up Husky pre-commit hooks 72 | - `yarn precommit` - Runs Lint Staged for staged files 73 | 74 | ## 📋 Project Structure 75 | 76 | ``` 77 | next-typescript-tailwindcss-sass-starter/ 78 | ├── app/ # Next.js App Router files 79 | │ ├── layout.tsx # Root layout component 80 | │ ├── page.tsx # Homepage component 81 | ├── __tests__/ # Test files 82 | ├── styles/ # Global styles 83 | │ ├── globals.scss # Global SCSS with Tailwind imports 84 | ├── public/ # Static assets 85 | ├── .husky/ # Husky git hooks 86 | ``` 87 | 88 | ## 🧪 Testing 89 | 90 | This starter uses Vitest and React Testing Library for testing. An example test is included in the `__tests__` directory. 91 | 92 | ```bash 93 | # Run tests 94 | yarn test 95 | ``` 96 | 97 | ## 💅 Styling 98 | 99 | This starter combines TailwindCSS and Sass for a powerful styling workflow: 100 | 101 | - TailwindCSS for utility-first CSS 102 | - Sass for more complex styling needs 103 | - Organized global styles in the `styles` directory 104 | 105 | ## 🛠️ Development Tools 106 | 107 | - **ESLint**: Configured with Next.js recommended rules 108 | - **Prettier**: Maintains consistent code style 109 | - **Husky**: Runs checks before commits 110 | - **Lint Staged**: Runs linters against staged git files 111 | 112 | ## 📚 Learn More About Next.js 113 | 114 | To learn more about Next.js, take a look at the following resources: 115 | 116 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 117 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 118 | 119 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 120 | 121 | ## 📄 License 122 | 123 | This project is licensed under the MIT License. 124 | -------------------------------------------------------------------------------- /__tests__/page.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react' 2 | import { expect, test } from 'vitest' 3 | 4 | import Page from '../app/page' 5 | 6 | test('Page', () => { 7 | render() 8 | expect(screen.getByRole('heading', { level: 1, name: 'Welcome to Next.js!' })).toBeDefined() 9 | }) -------------------------------------------------------------------------------- /app/head.tsx: -------------------------------------------------------------------------------- 1 | export default function Head() { 2 | return ( 3 | <> 4 | Create Next App 5 | 6 | 7 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Inter } from "next/font/google"; 3 | 4 | import "@/styles/globals.scss"; 5 | 6 | // If loading a variable font, you don't need to specify the font weight 7 | const inter = Inter({ subsets: ["latin"] }); 8 | 9 | export default function RootLayout({ 10 | children, 11 | }: { 12 | children: React.ReactNode; 13 | }) { 14 | return ( 15 | 16 | 17 | Mike van Peeren 18 | 19 | 20 |
21 |
22 | {/* Here you can place your Navigation */} 23 |
24 |
{children}
25 |
26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |
5 |

6 | Welcome to Next.js! 7 |

8 |

9 | Get started by editing{" "} 10 | 11 | pages/index.js 12 | 13 |

14 |
15 | 19 |

Documentation →

20 |

21 | Find in-depth information about Next.js features and API. 22 |

23 |
24 | 25 | 29 |

Learn →

30 |

31 | Learn about Next.js in an interactive course with quizzes! 32 |

33 |
34 | 35 | 39 |

Examples →

40 |

41 | Discover and deploy boilerplate example Next.js projects. 42 |

43 |
44 | 45 | 49 |

Deploy →

50 |

51 | Instantly deploy your Next.js site to a public URL with Vercel. 52 |

53 |
54 |
55 |
56 |
57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import simpleImportSort from "eslint-plugin-simple-import-sort"; 2 | import path from "node:path"; 3 | import { fileURLToPath } from "node:url"; 4 | import js from "@eslint/js"; 5 | import { FlatCompat } from "@eslint/eslintrc"; 6 | 7 | const __filename = fileURLToPath(import.meta.url); 8 | const __dirname = path.dirname(__filename); 9 | const compat = new FlatCompat({ 10 | baseDirectory: __dirname, 11 | recommendedConfig: js.configs.recommended, 12 | allConfig: js.configs.all 13 | }); 14 | 15 | const config = [ 16 | ...compat.extends("eslint:recommended", "next/core-web-vitals", "prettier"), 17 | { 18 | plugins: { 19 | "simple-import-sort": simpleImportSort, 20 | }, 21 | }, 22 | { 23 | files: ["**/*.ts", "**/*.tsx"], 24 | 25 | rules: { 26 | "simple-import-sort/imports": ["error", { 27 | groups: [ 28 | ["^react", "^next"], 29 | ["^@?\\w"], 30 | ["^(@/components|@/utils)(/.*|$)"], 31 | ["^\\/public"], 32 | ["^\\u0000"], 33 | ["^\\.\\.(?!/?$)", "^\\.\\./?$"], 34 | ["^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"], 35 | ["^.+\\.s?css$"], 36 | ], 37 | }], 38 | }, 39 | }, 40 | ]; 41 | 42 | export default config -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const withBundleAnalyzer = require("@next/bundle-analyzer")({ 3 | enabled: process.env.ANALYZE === "true", 4 | }); 5 | 6 | module.exports = withBundleAnalyzer({ 7 | reactStrictMode: true, 8 | sassOptions: { 9 | includePaths: [path.join(__dirname, "styles")], 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-typescript-tailwindcss-sass-starter", 3 | "description": "Use TypeScript, TailwindCSS & Sass to quick start your new Next.js app!!", 4 | "version": "1.0.0", 5 | "author": { 6 | "name": "Mike van Peeren", 7 | "url": "https://github.com/MikevPeeren" 8 | }, 9 | "license": "MIT", 10 | "keywords": [ 11 | "tailwindcss", 12 | "next", 13 | "next.js", 14 | "starter", 15 | "typescript", 16 | "prettier", 17 | "eslint", 18 | "sass", 19 | "react", 20 | "husky", 21 | "postcss", 22 | "sass", 23 | "nextjs starter", 24 | "tailwindcss starter", 25 | "nextjs tailwindcss starter", 26 | "nextjs-tailwind-starter" 27 | ], 28 | "repository": { 29 | "type": "git", 30 | "url": "git@github.com:MikevPeeren/next-typescript-tailwindcss-sass-starter.git" 31 | }, 32 | "scripts": { 33 | "dev": "next dev", 34 | "build": "next build", 35 | "start": "next start", 36 | "lint": "next lint", 37 | "test": "vitest", 38 | "format": "prettier --write .", 39 | "prepare": "husky", 40 | "precommit": "lint-staged" 41 | }, 42 | "lint-staged": { 43 | "*.{js,ts,jsx,tsx}": [ 44 | "eslint --fix" 45 | ], 46 | "*.{html,js,ts}": [ 47 | "prettier --write" 48 | ] 49 | }, 50 | "dependencies": { 51 | "@next/bundle-analyzer": "^15.3.3", 52 | "eslint-plugin-simple-import-sort": "^12.1.1", 53 | "next": "^15.3.3", 54 | "react": "^19.1.0", 55 | "react-dom": "^19.1.0", 56 | "sass": "^1.89.1" 57 | }, 58 | "devDependencies": { 59 | "@testing-library/dom": "^10.4.0", 60 | "@testing-library/react": "^16.3.0", 61 | "@types/node": "^22.15.30", 62 | "@types/react": "^19.1.6", 63 | "@vitejs/plugin-react": "^4.5.1", 64 | "autoprefixer": "^10.4.21", 65 | "eslint": "9.28.0", 66 | "eslint-config-next": "^15.3.3", 67 | "eslint-config-prettier": "^10.1.5", 68 | "husky": "^9.1.7", 69 | "jsdom": "^26.1.0", 70 | "lint-staged": "^15.5.2", 71 | "postcss": "^8.5.4", 72 | "prettier": "^3.5.3", 73 | "prettier-plugin-tailwindcss": "^0.6.12", 74 | "tailwindcss": "^4.1.7", 75 | "@tailwindcss/postcss": "^4.1.8", 76 | "typescript": "^5.8.3", 77 | "vitest": "^3.2.2" 78 | }, 79 | "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" 80 | } 81 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | "@tailwindcss/postcss": {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MikevPeeren/next-typescript-tailwindcss-sass-starter/68e22dd008086e02fac63ee89d942e85ee21cfdf/public/favicon.ico -------------------------------------------------------------------------------- /public/vercel-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /styles/globals.scss: -------------------------------------------------------------------------------- 1 | @use "tailwindcss"; 2 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ["./app/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}"], 3 | darkMode: "class", // or 'media' or 'class' 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/*": [ 6 | "*" 7 | ], 8 | "@/components/*": [ 9 | "components/*" 10 | ], 11 | "@/styles/*": [ 12 | "styles/*" 13 | ] 14 | }, 15 | "target": "es6", 16 | "lib": [ 17 | "dom", 18 | "dom.iterable", 19 | "esnext" 20 | ], 21 | "allowJs": true, 22 | "skipLibCheck": true, 23 | "strict": false, 24 | "forceConsistentCasingInFileNames": true, 25 | "noEmit": true, 26 | "incremental": true, 27 | "esModuleInterop": true, 28 | "module": "esnext", 29 | "moduleResolution": "node", 30 | "resolveJsonModule": true, 31 | "isolatedModules": true, 32 | "jsx": "preserve", 33 | "plugins": [ 34 | { 35 | "name": "next" 36 | } 37 | ], 38 | "strictNullChecks": true 39 | }, 40 | "include": [ 41 | "next-env.d.ts", 42 | "**/*.ts", 43 | "**/*.tsx", 44 | ".next/types/**/*.ts" 45 | ], 46 | "exclude": [ 47 | "node_modules" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import { defineConfig } from "vite"; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | test: { 7 | environment: "jsdom", 8 | }, 9 | }); 10 | --------------------------------------------------------------------------------