{"id":23407196,"url":"https://github.com/burgil/nextjs-cloudflare-fullstack","last_synced_at":"2025-06-29T18:33:11.394Z","repository":{"id":268980672,"uuid":"906057965","full_name":"burgil/NextJS-CloudFlare-FullStack","owner":"burgil","description":"Did you think CloudFlare Pages can only run static html files? Think again! Through the power of CloudfFlare Functions we are able to deploy a full-stack application with a backend and a frontend directly connected. (Using CloudFlare Workers + Pages through Functions) - NEW! NextJS Support","archived":false,"fork":false,"pushed_at":"2024-12-20T12:18:16.000Z","size":182,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-14T18:49:36.988Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/burgil.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-20T04:35:28.000Z","updated_at":"2024-12-20T05:11:29.000Z","dependencies_parsed_at":"2024-12-20T05:28:01.248Z","dependency_job_id":"71641f31-bce8-4e00-80b7-563dd1c1d772","html_url":"https://github.com/burgil/NextJS-CloudFlare-FullStack","commit_stats":null,"previous_names":["burgil/nextjs-cloudflare-fullstack"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burgil%2FNextJS-CloudFlare-FullStack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burgil%2FNextJS-CloudFlare-FullStack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burgil%2FNextJS-CloudFlare-FullStack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burgil%2FNextJS-CloudFlare-FullStack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/burgil","download_url":"https://codeload.github.com/burgil/NextJS-CloudFlare-FullStack/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247947859,"owners_count":21023066,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-22T14:17:55.450Z","updated_at":"2025-04-09T00:08:10.907Z","avatar_url":"https://github.com/burgil.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Instructions to use Next.JS with CF FullStack\n\n[Demo](https://nextjscfsupport.pages.dev)\n\n![Next.JS with CF FullStack](preview.png)\n\n**Buy Why?**\n\n**VERCEL:**\n\n`16MB per request x 1 million requests = 16 million megabytes / 1024MB = 15625TB x $20 per 1 TB = 312,500$ on vercel`\n\n`1MB per request x 1 million requests = 1 million megabytes / 1024MB = 976TB x $20 per 1 TB = 19,520$ on vercel`\n\n**CLOUDFLARE:**\n\n`any MB per request x 1 million requests = free - NO CREDIT CARD REQUIRED`\n\n**THE CATCH:**\n\n(+$0.60 per additional million and only for backend traffic, AKA cloudflare workers - And for the frontend traffic it's 100% free - AKA cloudflare pages - Frontend traffic means all your HTML,CSS,JS,PNG and etc files)\n\n*You also get a free database to use... Look nothing is really free, but it's the cheapest by far. And no credit card is required to start!*\n\n\u003e THANK YOU CLOUDFLARE FOR ALLOWING ME TO GROW (REALISTICALLY) AS I GO ⛅🌩🙏\n\n*Only 500 builds per month? And what do they mean by 1 build at a time?*\n\n\u003e A build counts for when you run `pnpm deploy`, it takes around 30 seconds to complete, during this 30 seconds only 1 built can be made, and only 500 builds per month, look they need to distribute your HTML,CSS,JS,PNG.. files on all their 275+ data centers (tons of computers) and you get it for free so no complains! or just pay them $20 lol!\n\n**Don't believe me?**\n\n*Check for yourself* [here](https://workers.cloudflare.com/) and [here](https://pages.cloudflare.com/) (Scroll down for the pricing - **No credit card required to start**)\n\n\u003e [!IMPORTANT]  \n\u003e You don't have to clone this repository, The entire reproduction steps can be found below!\n\n## Next.JS SSG (Static Site Generation)\n\nBy default, Next.js pre-renders pages using [Static Generation](https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation) without fetching data. Here's an example:\n\n```ts\nfunction About() {\n  return \u003cdiv\u003eAbout\u003c/div\u003e\n}\n \nexport default About\n```\n\n**But, You need to understand [Static Exports](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports)**\n\n## Instructions\n\n### 1. Create a new Next.JS project or use an existing one\n\n```bash\nnpx create-next-app@latest\n\ncd my-app\n\npnpm dev\n\nhttp://localhost:3000\n\nCTRL+C\n```\n\n### 2. Install the workers types\n\n```bash\npnpm add -D @cloudflare/workers-types\n```\n\n### 3. Create wrangler.toml\n\nModify the name in `wrangler.toml`\n\n```toml\n#:schema node_modules/wrangler/config-schema.json\nname = \"nextjscfsupport\"\ncompatibility_date = \"2024-12-20\"\npages_build_output_dir = \"./out\"\n# compatibility_flags = [\"nodejs_compat\"]\n\n[vars]\nAPI_HOST = \"example.com\"\nAPI_ACCOUNT_ID = \"example_user\"\nSERVICE_X_DATA = { URL = \"service-x-api.dev.example\", MY_ID = 123 }\n\n# Automatically place your workloads in an optimal location to minimize latency.\n# If you are running back-end logic in a Pages Function, running it closer to your back-end infrastructure\n# rather than the end user may result in better performance.\n# Docs: https://developers.cloudflare.com/pages/functions/smart-placement/#smart-placement\n# [placement]\n# mode = \"smart\"\n\n# Variable bindings. These are arbitrary, plaintext strings (similar to environment variables)\n# Docs:\n# - https://developers.cloudflare.com/pages/functions/bindings/#environment-variables\n# Note: Use secrets to store sensitive data.\n# - https://developers.cloudflare.com/pages/functions/bindings/#secrets\n# [vars]\n# MY_VARIABLE = \"production_value\"\n\n# Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflare’s global network\n# Docs: https://developers.cloudflare.com/pages/functions/bindings/#workers-ai\n# [ai]\n# binding = \"AI\"\n\n# Bind a D1 database. D1 is Cloudflare’s native serverless SQL database.\n# Docs: https://developers.cloudflare.com/pages/functions/bindings/#d1-databases\n# [[d1_databases]]\n# binding = \"EXAMPLED1\"\n# database_name = \"example-d1\"\n# database_id = \"1-2-3-4-5\"\n# # preview_database_id = \"DB\" # Required for Pages local development\n\n# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.\n# Durable Objects can live for as long as needed. Use these when you need a long-running \"server\", such as in realtime apps.\n# Docs: https://developers.cloudflare.com/workers/runtime-apis/durable-objects\n# [[durable_objects.bindings]]\n# name = \"MY_DURABLE_OBJECT\"\n# class_name = \"MyDurableObject\"\n# script_name = 'my-durable-object'\n\n# Bind a KV Namespace. Use KV as persistent storage for small key-value pairs.\n# Docs: https://developers.cloudflare.com/pages/functions/bindings/#kv-namespaces\n# [[kv_namespaces]]\n# binding = \"EXAMPLEKV\"\n# id = \"id here\"\n\n# Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer.\n# Docs: https://developers.cloudflare.com/pages/functions/bindings/#queue-producers\n# [[queues.producers]]\n# binding = \"MY_QUEUE\"\n# queue = \"my-queue\"\n\n# Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files.\n# Docs: https://developers.cloudflare.com/pages/functions/bindings/#r2-buckets\n# [[r2_buckets]]\n# binding = \"MY_BUCKET\"\n# bucket_name = \"my-bucket\"\n\n# Bind another Worker service. Use this binding to call another Worker without network overhead.\n# Docs: https://developers.cloudflare.com/pages/functions/bindings/#service-bindings\n# [[services]]\n# binding = \"MY_SERVICE\"\n# service = \"my-service\"\n\n# To use different bindings for preview and production environments, follow the examples below.\n# When using environment-specific overrides for bindings, ALL bindings must be specified on a per-environment basis.\n# Docs: https://developers.cloudflare.com/pages/functions/wrangler-configuration#environment-specific-overrides\n\n######## PREVIEW environment config ########\n\n# [env.preview.vars]\n# API_KEY = \"xyz789\"\n\n# [[env.preview.kv_namespaces]]\n# binding = \"MY_KV_NAMESPACE\"\n# id = \"\u003cPREVIEW_NAMESPACE_ID\u003e\"\n\n######## PRODUCTION environment config ########\n\n# [env.production.vars]\n# API_KEY = \"abc123\"\n\n# [[env.production.kv_namespaces]]\n# binding = \"MY_KV_NAMESPACE\"\n# id = \"\u003cPRODUCTION_NAMESPACE_ID\u003e\"\n```\n\n### 4. Add to .gitignore\n\n```text\n# wrangler files\n.wrangler\n.dev.vars\n```\n\n### 5. Modify package.json\n\n```json\n  \"scripts\": {\n    \"dev\": \"next dev --turbopack\",\n    \"start\": \"next dev --turbopack\",\n    \"start:backend\": \"pnpm dlx wrangler pages dev pages\",\n    \"build\": \"next build\",\n    \"deploy\": \"next build \u0026\u0026 pnpm dlx wrangler pages deploy ./out\",\n    \"deploy:test\": \"pnpm dlx wrangler pages dev ./out\",\n    \"lint\": \"next lint\"\n```\n\n### 6. Modify next.config.ts\n\n```ts\nimport type { NextConfig } from \"next\";\n\n// Since we want the development server to redirect traffic to /api/ from the frontend at http://localhost:3000 to the backend at http://localhost:8788\n// We need to set up \"rewrites\", NextJS warns you that these rewrites will not work in production after you build\n// But we don't care because wrangler automatically binds the \"functions\" directory to the frontend on production\n// We just need it to work in development too\nconst warn = console.warn;\nconsole.warn = (...args) =\u003e {\n  if (args[0].trim().includes('Specified \"rewrites\" will not automatically work with \"output: export\". See more info here: https://nextjs.org/docs/messages/export-no-custom-routes')) return;\n  if (args[0].trim().includes('rewrites, redirects, and headers are not applied when exporting your application, detected (rewrites). See more info here: https://nextjs.org/docs/messages/export-no-custom-routes')) return;\n  warn(...args);\n}\n\nconst nextConfig: NextConfig = {\n  output: 'export',\n\n  // https://stackoverflow.com/questions/60925133/proxy-to-backend-with-default-next-js-dev-server\n  async rewrites() {\n    return [\n      {\n        source: \"/api/:path*/\",\n        destination: `${process.env.NEXT_PUBLIC_BASE_URL || 'http://127.0.0.1:8788'}/api/:path*/`,\n      },\n    ];\n  },\n\n  // Change links `/me` -\u003e `/me/` and emit `/me.html` -\u003e `/me/index.html`\n  trailingSlash: true,\n\n  // Optional: Prevent automatic `/me` -\u003e `/me/`, instead preserve `href`\n  // skipTrailingSlashRedirect: true,\n\n  // Optional: Change the output directory `out` -\u003e `dist`\n  // distDir: 'dist',\n};\n\nexport default nextConfig;\n\n```\n\n### 7. Modify tsconfig.json\n\n```json\n{\n  \"compilerOptions\": {\n  ...\n    \"types\": [\"@cloudflare/workers-types\"],\n```\n\n### 8. Create functions/api/login.ts\n\nCreate your first backend route for `/api/login`\n\nFor now I used an example GET request but you can google `\"cloudflare workers/functions post request\"`, gpt it or ask Burgil how to use POST requests..\n\n```ts\ninterface Env {\n    API_HOST: string;\n}\n\nexport const onRequest: PagesFunction\u003cEnv\u003e = async (context) =\u003e {\n    return new Response(`Hello from backend! TODO Login Route! - API host: ${context.env.API_HOST}`);\n};\n```\n\nEnjoy TypeScript support out of the box! **(Rare Feature!)**\n\nYou have full access to all CF Workers types, For example:\n\n```ts\ninterface Env {\n    KVDB: KVNamespace;\n    D1DB: D1Database;\n    API_KEY: string;\n}\n```\n\n### 9. To start the frontend run\n\n```bash\npnpm start\n```\n\n[http://localhost:3000](http://localhost:3000)\n\n### 10. To start the backend run\n\n```bash\npnpm start:backend\n```\n\n[http://localhost:8788/api/login](http://localhost:8788/api/login)\n\n### 11. To deploy run\n\n```bash\npnpm run deploy\n```\n\n### 12. Connecting the Frontend with the Backend\n\nA) Create `my-app\\src\\app\\LoginButton.tsx` or wherever else you want it\n\n```ts\n\"use client\"\n\nexport default function LoginButton() {\n\n    async function handleLogin() {\n        try {\n            const response = await fetch(\"/api/login\"/*, {\n                method: \"POST\",\n                body: JSON.stringify({\n                    email,\n                    pass\n                })\n            }*/)\n            const data = await response.text();\n            alert(data)\n        } catch (e) {\n            console.log(\"Failed to login!\", e);\n            alert(\"Failed to login! Check the console...\");\n        }\n    }\n\n    return (\n        \u003cbutton onClick={handleLogin} className=\"rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44\"\u003e\n            Test Login API\n        \u003c/button\u003e\n    )\n}\n```\n\nB) Modify `my-app\\src\\app\\page.tsx`\n\n```diff\n+ import LoginButton from \"./LoginButton\";\n-        \u003cdiv className=\"flex gap-4 items-center flex-col sm:flex-row\"\u003e\n-          \u003ca\n-            className=\"rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5\"\n-            href=\"https://vercel.com/new?utm_source=create-next-app\u0026utm_medium=appdir-template-tw\u0026utm_campaign=create-next-app\"\n-            target=\"_blank\"\n-            rel=\"noopener noreferrer\"\n-          \u003e\n-            \u003cImage\n-              className=\"dark:invert\"\n-              src=\"/vercel.svg\"\n-              alt=\"Vercel logomark\"\n-              width={20}\n-              height={20}\n-            /\u003e\n-            Deploy now\n-          \u003c/a\u003e\n-          \u003ca\n-            className=\"rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44\"\n-            href=\"https://nextjs.org/docs?utm_source=create-next-app\u0026utm_medium=appdir-template-tw\u0026utm_campaign=create-next-app\"\n-            target=\"_blank\"\n-            rel=\"noopener noreferrer\"\n-          \u003e\n-            Read our docs\n-          \u003c/a\u003e\n-        \u003c/div\u003e\n+        \u003cdiv className=\"flex gap-4 items-center sm:flex-row\"\u003e\n+          \u003ca\n+            className=\"rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5\"\n+            href=\"https://dash.cloudflare.com/\"\n+            target=\"_blank\"\n+            rel=\"noopener noreferrer\"\n+          \u003e\n+            \u003cImage\n+              className=\"dark:invert\"\n+              src=\"/vercel.svg\"\n+              alt=\"Vercel logomark\"\n+              width={20}\n+              height={20}\n+            /\u003e\n+            Deploy now\n+          \u003c/a\u003e\n+          \u003ca\n+            className=\"rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44\"\n+            href=\"https://nextjs.org/docs?utm_source=create-next-app\u0026utm_medium=appdir-template-tw\u0026utm_campaign=create-next-app\"\n+            target=\"_blank\"\n+            rel=\"noopener noreferrer\"\n+          \u003e\n+            Read NextJS docs\n+          \u003c/a\u003e\n+        \u003c/div\u003e\n+        \u003cdiv className=\"flex gap-4 items-center sm:flex-row\"\u003e\n\n+          \u003cLoginButton /\u003e\n\n+          \u003ca\n+            className=\"rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44\"\n+            href=\"https://pages.cloudflare.com/\"\n+            target=\"_blank\"\n+            rel=\"noopener noreferrer\"\n+          \u003e\n+            CF Pages\n+          \u003c/a\u003e\n+          \u003ca\n+            className=\"rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44\"\n+            href=\"https://workers.cloudflare.com/\"\n+            target=\"_blank\"\n+            rel=\"noopener noreferrer\"\n+          \u003e\n+            CF Workers\n+          \u003c/a\u003e\n+        \u003c/div\u003e\n```\n\n### 13. Installation Logs\n\nnpx create-next-app@latest\n\n```text\nPS C:\\Projects\\nextjs\u003e npx create-next-app@latest\nNeed to install the following packages:\ncreate-next-app@15.1.2\nOk to proceed? (y) y\n\n√ What is your project named? ... my-app\n√ Would you like to use TypeScript? ... No / Yes\n√ Would you like to use ESLint? ... No / Yes\n√ Would you like to use Tailwind CSS? ... No / Yes\n√ Would you like your code inside a `src/` directory? ... No / Yes\n√ Would you like to use App Router? (recommended) ... No / Yes\n√ Would you like to use Turbopack for `next dev`? ... No / Yes\n√ Would you like to customize the import alias (`@/*` by default)? ... No / Yes\n√ What import alias would you like configured? ... @/*\nCreating a new Next.js app in C:\\Projects\\nextjs\\my-app.\n\nUsing npm.\n\nInitializing project with template: app-tw\n\n\nInstalling dependencies:\n- react\n- react-dom\n- next\n\nInstalling devDependencies:\n- typescript\n- @types/node\n- @types/react\n- @types/react-dom\n- postcss\n- tailwindcss\n- eslint\n- eslint-config-next\n- @eslint/eslintrc\n\n\nadded 370 packages, and audited 371 packages in 1m\n\n140 packages are looking for funding\n  run `npm fund` for details\n\nfound 0 vulnerabilities\nInitialized a git repository.\n\nSuccess! Created my-app at C:\\Projects\\nextjs\\my-app\n```\n\n### 14. Build + Deploy Logs\n\npnpm run deploy\n\n```text\nPS A:\\Projects\\nextjs\\my-app\u003e pnpm run deploy\n\n\u003e my-app@0.1.0 deploy A:\\Projects\\nextjs\\my-app\n\u003e next build \u0026\u0026 pnpm dlx wrangler pages deploy ./out\n\n   ▲ Next.js 15.1.2\n\n   Creating an optimized production build ...\n ✓ Compiled successfully\n ✓ Linting and checking validity of types    \n ✓ Collecting page data\n ✓ Generating static pages (5/5)\n ✓ Collecting build traces    \n ✓ Exporting (3/3)\n ✓ Finalizing page optimization\n\nRoute (app)                              Size     First Load JS\n┌ ○ /                                    5.82 kB         111 kB\n└ ○ /_not-found                          977 B           106 kB\n+ First Load JS shared by all            105 kB\n  ├ chunks/35-2e16dc7683c22009.js        50.6 kB\n  ├ chunks/b26ba64e-d9c16b6181b85011.js  52.9 kB\n  └ other shared chunks (total)          1.95 kB\n\n\n○  (Static)  prerendered as static content\n\n▲ [WARNING] Warning: Your working directory is a git repo and has uncommitted changes\n\n  To silence this warning, pass in --commit-dirty=true\n\n\n✨ Compiled Worker successfully\n✨ Success! Uploaded 4 files (28 already uploaded) (1.71 sec)\n\n✨ Uploading Functions bundle\n🌎 Deploying...\n✨ Deployment complete! Take a peek over at https://535b50d2.nextjscfsupport.pages.dev\n```\n\nIgnore the `535b50d2` part.\n\nNow open your website, in my case [https://nextjscfsupport.pages.dev](https://nextjscfsupport.pages.dev)\n\nClick the Test Login API button - As you can see it works in both production and development.\n\nTo add a .com domain simply [get one](https://domains.cloudflare.com/) and connect it in the [dashboard](https://dash.cloudflare.com/)\n\n\u003e [!NOTE]  \n\u003e Note: Creating a `.pages.dev` domain initially takes a lot of time so wait like 5 minutes before the page is working\n\n### 15. What's next?\n\n1. Learn about D1 / KV databases to get the best database on the planet.\n\n2. Make a POST route that returns JSON and call it from the client.\n\n3. Ask burgil how to connect the D1 / KV database to your login system.\n\n4. Enjoy your super fast and super cheap and efficient website\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburgil%2Fnextjs-cloudflare-fullstack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fburgil%2Fnextjs-cloudflare-fullstack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburgil%2Fnextjs-cloudflare-fullstack/lists"}