diff --git a/.netlify/state.json b/.netlify/state.json
new file mode 100644
index 0000000000..78ad1848cb
--- /dev/null
+++ b/.netlify/state.json
@@ -0,0 +1,3 @@
+{
+ "siteId": "b7ec5732-32dc-4d00-9108-051d100b6d2e"
+}
\ No newline at end of file
diff --git a/demo/.gitignore b/demo/.gitignore
new file mode 100644
index 0000000000..852cbb950f
--- /dev/null
+++ b/demo/.gitignore
@@ -0,0 +1,38 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# vercel
+.vercel
+
+netlify/functions
+.netlify/functions
+.netlify/cache
\ No newline at end of file
diff --git a/demo/README.md b/demo/README.md
new file mode 100644
index 0000000000..b12f3e33e7
--- /dev/null
+++ b/demo/README.md
@@ -0,0 +1,34 @@
+This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
+
+[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
+
+The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
diff --git a/demo/components/Header.js b/demo/components/Header.js
new file mode 100644
index 0000000000..31c6d3f6eb
--- /dev/null
+++ b/demo/components/Header.js
@@ -0,0 +1,3 @@
+export default function Header() {
+ return
header
+}
diff --git a/demo/netlify.toml b/demo/netlify.toml
new file mode 100644
index 0000000000..bffbe00028
--- /dev/null
+++ b/demo/netlify.toml
@@ -0,0 +1,11 @@
+[build]
+command = "npm run build"
+publish = "out/"
+# Build for updates outside of the site
+ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF .."
+
+[[plugins]]
+package = ".."
+
+[[plugins]]
+package = "@netlify/plugin-local-install-core"
\ No newline at end of file
diff --git a/demo/next.config.js b/demo/next.config.js
new file mode 100644
index 0000000000..cceffb934b
--- /dev/null
+++ b/demo/next.config.js
@@ -0,0 +1,5 @@
+
+ module.exports = {
+ target: 'serverless'
+ }
+
\ No newline at end of file
diff --git a/demo/package.json b/demo/package.json
new file mode 100644
index 0000000000..b26d22b5e7
--- /dev/null
+++ b/demo/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "demo",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start"
+ },
+ "dependencies": {
+ "next": "10.2.3",
+ "react": "17.0.2",
+ "react-dom": "17.0.2"
+ }
+}
diff --git a/demo/pages/_app.js b/demo/pages/_app.js
new file mode 100644
index 0000000000..1e1cec9242
--- /dev/null
+++ b/demo/pages/_app.js
@@ -0,0 +1,7 @@
+import '../styles/globals.css'
+
+function MyApp({ Component, pageProps }) {
+ return
+}
+
+export default MyApp
diff --git a/demo/pages/api/hello-background.js b/demo/pages/api/hello-background.js
new file mode 100644
index 0000000000..5808ea36cf
--- /dev/null
+++ b/demo/pages/api/hello-background.js
@@ -0,0 +1,5 @@
+export default (req, res) => {
+ res.setHeader('Content-Type', 'application/json')
+ res.status(200)
+ res.json({ message: 'hello world :)' })
+}
diff --git a/demo/pages/api/hello.js b/demo/pages/api/hello.js
new file mode 100644
index 0000000000..9987aff4c3
--- /dev/null
+++ b/demo/pages/api/hello.js
@@ -0,0 +1,5 @@
+// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
+
+export default (req, res) => {
+ res.status(200).json({ name: 'John Doe' })
+}
diff --git a/demo/pages/api/shows/[...params].js b/demo/pages/api/shows/[...params].js
new file mode 100644
index 0000000000..e8f510d08b
--- /dev/null
+++ b/demo/pages/api/shows/[...params].js
@@ -0,0 +1,26 @@
+export default async (req, res) => {
+ // Respond with JSON
+ res.setHeader('Content-Type', 'application/json')
+
+ // Get the params and query string parameters
+ const { query } = req
+ const { params, ...queryStringParams } = query
+
+ // Get the ID of the show
+ const id = params[0]
+
+ // Get the data
+ const fetchRes = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await fetchRes.json()
+
+ // If show was found, return it
+ if (fetchRes.status == 200) {
+ res.status(200)
+ res.json({ params, queryStringParams, show: data })
+ }
+ // If show was not found, return error
+ else {
+ res.status(404)
+ res.json({ error: 'Show not found' })
+ }
+}
diff --git a/demo/pages/api/shows/[id].js b/demo/pages/api/shows/[id].js
new file mode 100644
index 0000000000..54f8a41b73
--- /dev/null
+++ b/demo/pages/api/shows/[id].js
@@ -0,0 +1,23 @@
+export default async (req, res) => {
+ // Respond with JSON
+ res.setHeader('Content-Type', 'application/json')
+
+ // Get the ID of the show
+ const { query } = req
+ const { id } = query
+
+ // Get the data
+ const fetchRes = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await fetchRes.json()
+
+ // If show was found, return it
+ if (fetchRes.status == 200) {
+ res.status(200)
+ res.json({ show: data })
+ }
+ // If show was not found, return error
+ else {
+ res.status(404)
+ res.json({ error: 'Show not found' })
+ }
+}
diff --git a/demo/pages/deep/import.js b/demo/pages/deep/import.js
new file mode 100644
index 0000000000..e2cb184911
--- /dev/null
+++ b/demo/pages/deep/import.js
@@ -0,0 +1,40 @@
+import Link from 'next/link'
+import dynamic from 'next/dynamic'
+const Header = dynamic(() => import(/* webpackChunkName: 'header' */ '../../components/Header'), { ssr: true })
+
+const Show = ({ show }) => (
+
+
+
+ This page uses getInitialProps() to fetch the show with the ID provided in the URL: /shows/:id
+
+ Refresh the page to see server-side rendering in action.
+
+ You can also try changing the ID to any other number between 1-10000.
+
+)
+
+export const getServerSideProps = async ({ params }) => {
+ const res = await fetch('https://api.tvmaze.com/shows/42')
+ const data = await res.json()
+
+ return {
+ props: {
+ show: data,
+ },
+ }
+}
+
+export default Show
diff --git a/demo/pages/getServerSideProps/[id].js b/demo/pages/getServerSideProps/[id].js
new file mode 100644
index 0000000000..3487e968de
--- /dev/null
+++ b/demo/pages/getServerSideProps/[id].js
@@ -0,0 +1,53 @@
+import Error from 'next/error'
+import Link from 'next/link'
+
+const Show = ({ errorCode, show }) => {
+ // If show item was not found, render 404 page
+ if (errorCode) {
+ return
+ }
+
+ // Otherwise, render show
+ return (
+
+
+ This page uses getInitialProps() to fetch the show with the ID provided in the URL: /shows/:id
+
+ Refresh the page to see server-side rendering in action.
+
+ You can also try changing the ID to any other number between 1-10000.
+
+ )
+}
+
+export const getServerSideProps = async ({ params }) => {
+ // The ID to render
+ const { id } = params
+
+ const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await res.json()
+
+ // Set error code if show item could not be found
+ const errorCode = res.status > 200 ? res.status : false
+
+ return {
+ props: {
+ errorCode,
+ show: data,
+ },
+ }
+}
+
+export default Show
diff --git a/demo/pages/getServerSideProps/all/[[...slug]].js b/demo/pages/getServerSideProps/all/[[...slug]].js
new file mode 100644
index 0000000000..76230a787c
--- /dev/null
+++ b/demo/pages/getServerSideProps/all/[[...slug]].js
@@ -0,0 +1,53 @@
+import Error from 'next/error'
+import Link from 'next/link'
+
+const Show = ({ errorCode, show }) => {
+ // If show item was not found, render 404 page
+ if (errorCode) {
+ return
+ }
+
+ // Otherwise, render show
+ return (
+
+
+ This page uses getInitialProps() to fetch the show with the ID provided in the URL: /shows/:id
+
+ Refresh the page to see server-side rendering in action.
+
+ You can also try changing the ID to any other number between 1-10000.
+
+ )
+}
+
+export const getServerSideProps = async ({ params }) => {
+ // The ID to render
+ const { slug } = params
+
+ const res = await fetch(`https://api.tvmaze.com/shows/${slug[0]}`)
+ const data = await res.json()
+
+ // Set error code if show item could not be found
+ const errorCode = res.status > 200 ? res.status : false
+
+ return {
+ props: {
+ errorCode,
+ show: data,
+ },
+ }
+}
+
+export default Show
diff --git a/demo/pages/getServerSideProps/static.js b/demo/pages/getServerSideProps/static.js
new file mode 100644
index 0000000000..dfbce6da56
--- /dev/null
+++ b/demo/pages/getServerSideProps/static.js
@@ -0,0 +1,37 @@
+import Link from 'next/link'
+
+const Show = ({ show }) => (
+
+
+ This page uses getInitialProps() to fetch the show with the ID provided in the URL: /shows/:id
+
+ Refresh the page to see server-side rendering in action.
+
+ You can also try changing the ID to any other number between 1-10000.
+
+)
+
+export async function getStaticProps(context) {
+ const res = await fetch(`https://api.tvmaze.com/shows/71`)
+ const data = await res.json()
+
+ return {
+ props: {
+ show: data,
+ },
+ revalidate: 1,
+ }
+}
+
+export default Show
diff --git a/demo/pages/getStaticProps/withFallback/[...slug].js b/demo/pages/getStaticProps/withFallback/[...slug].js
new file mode 100644
index 0000000000..8f004c9c01
--- /dev/null
+++ b/demo/pages/getStaticProps/withFallback/[...slug].js
@@ -0,0 +1,55 @@
+import { useRouter } from 'next/router'
+import Link from 'next/link'
+
+const Show = ({ show }) => {
+ const router = useRouter()
+
+ // This is never shown on Netlify. We just need it for NextJS to be happy,
+ // because NextJS will render a fallback HTML page.
+ if (router.isFallback) {
+ return
Loading...
+ }
+
+ return (
+
+
This page uses getStaticProps() to pre-fetch a TV show.
+ )
+}
+
+export async function getStaticPaths() {
+ // Set the paths we want to pre-render
+ const paths = [{ params: { slug: ['my', 'path', '1'] } }, { params: { slug: ['my', 'path', '2'] } }]
+
+ // We'll pre-render these paths at build time.
+ // { fallback: true } means other routes will be rendered at runtime.
+ return { paths, fallback: true }
+}
+
+export async function getStaticProps({ params }) {
+ // The ID to render
+ const { slug } = params
+ const id = slug[slug.length - 1]
+
+ const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await res.json()
+
+ return {
+ props: {
+ show: data,
+ },
+ }
+}
+
+export default Show
diff --git a/demo/pages/getStaticProps/withFallback/[id].js b/demo/pages/getStaticProps/withFallback/[id].js
new file mode 100644
index 0000000000..e872db34bf
--- /dev/null
+++ b/demo/pages/getStaticProps/withFallback/[id].js
@@ -0,0 +1,54 @@
+import { useRouter } from 'next/router'
+import Link from 'next/link'
+
+const Show = ({ show }) => {
+ const router = useRouter()
+
+ // This is never shown on Netlify. We just need it for NextJS to be happy,
+ // because NextJS will render a fallback HTML page.
+ if (router.isFallback) {
+ return
Loading...
+ }
+
+ return (
+
+
This page uses getStaticProps() to pre-fetch a TV show.
+ )
+}
+
+export async function getStaticPaths() {
+ // Set the paths we want to pre-render
+ const paths = [{ params: { id: '3' } }, { params: { id: '4' } }]
+
+ // We'll pre-render these paths at build time.
+ // { fallback: true } means other routes will be rendered at runtime.
+ return { paths, fallback: true }
+}
+
+export async function getStaticProps({ params }) {
+ // The ID to render
+ const { id } = params
+
+ const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await res.json()
+
+ return {
+ props: {
+ show: data,
+ },
+ }
+}
+
+export default Show
diff --git a/demo/pages/getStaticProps/withFallbackBlocking/[id].js b/demo/pages/getStaticProps/withFallbackBlocking/[id].js
new file mode 100644
index 0000000000..1cefa83122
--- /dev/null
+++ b/demo/pages/getStaticProps/withFallbackBlocking/[id].js
@@ -0,0 +1,55 @@
+import { useRouter } from 'next/router'
+import Link from 'next/link'
+
+const Show = ({ show }) => {
+ const router = useRouter()
+
+ // This is never shown on Netlify. We just need it for NextJS to be happy,
+ // because NextJS will render a fallback HTML page.
+ if (router.isFallback) {
+ return
Loading...
+ }
+
+ return (
+
+
This page uses getStaticProps() to pre-fetch a TV show.
+ )
+}
+
+export async function getStaticPaths() {
+ // Set the paths we want to pre-render
+ const paths = [{ params: { id: '3' } }, { params: { id: '4' } }]
+
+ // We'll pre-render these paths at build time.
+ // { fallback: blocking } means routes will be built when visited for the
+ // first time and only after it's built will the client receive a response
+ return { paths, fallback: 'blocking' }
+}
+
+export async function getStaticProps({ params }) {
+ // The ID to render
+ const { id } = params
+
+ const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await res.json()
+
+ return {
+ props: {
+ show: data,
+ },
+ }
+}
+
+export default Show
diff --git a/demo/pages/getStaticProps/withRevalidate/[id].js b/demo/pages/getStaticProps/withRevalidate/[id].js
new file mode 100644
index 0000000000..7bf51a7933
--- /dev/null
+++ b/demo/pages/getStaticProps/withRevalidate/[id].js
@@ -0,0 +1,44 @@
+import Link from 'next/link'
+
+const Show = ({ show }) => (
+
+
This page uses getStaticProps() to pre-fetch a TV show.
+)
+
+export async function getStaticPaths() {
+ // Set the paths we want to pre-render
+ const paths = [{ params: { id: '1' } }, { params: { id: '2' } }]
+
+ // We'll pre-render only these paths at build time.
+ // { fallback: false } means other routes should 404.
+ return { paths, fallback: true }
+}
+
+export async function getStaticProps({ params }) {
+ // The ID to render
+ const { id } = params
+
+ const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await res.json()
+
+ return {
+ props: {
+ show: data,
+ },
+ revalidate: 1,
+ }
+}
+
+export default Show
diff --git a/demo/pages/index.js b/demo/pages/index.js
new file mode 100644
index 0000000000..a62d6f99c9
--- /dev/null
+++ b/demo/pages/index.js
@@ -0,0 +1,127 @@
+import Link from 'next/link'
+
+const Index = ({ shows }) => (
+
+
+
+
NextJS on Netlify
+
+ This is a demo of a NextJS application with Server-Side Rendering (SSR).
+
+ It is hosted on Netlify.
+
+ Server-side rendering is handled by Netlify Functions.
+
+ Minimal configuration is required.
+
+ Everything is handled by the next-on-netlify npm
+ package.
+
+
+
1. Server-Side Rendering Made Easy
+
+ This page is server-side rendered.
+
+ It fetches a random list of five TV shows from the TVmaze REST API.
+
+ Refresh this page to see it change.
+
+ Dynamic pages, introduced in NextJS 9.2, are fully supported.
+
+ Click on a show to check out a server-side rendered page with dynamic routing (/shows/:id).
+
+ next-on-netlify automatically determines which pages are dynamic and which ones are static.
+
+ Only dynamic pages are server-side rendered.
+
+ Static pages are pre-rendered and served directly by Netlify's CDN.
+
+)
+
+Index.getInitialProps = async function () {
+ // Set a random page between 1 and 100
+ const randomPage = Math.floor(Math.random() * 100) + 1
+
+ // Get the data
+ const res = await fetch(`https://api.tvmaze.com/shows?page=${randomPage}`)
+ const data = await res.json()
+
+ return { shows: data.slice(0, 5) }
+}
+
+export default Index
diff --git a/demo/pages/shows/[...params].js b/demo/pages/shows/[...params].js
new file mode 100644
index 0000000000..c5a59b0da3
--- /dev/null
+++ b/demo/pages/shows/[...params].js
@@ -0,0 +1,61 @@
+import Error from 'next/error'
+import Link from 'next/link'
+
+const CatchAll = ({ errorCode, show, params }) => {
+ // If show item was not found, render 404 page
+ if (errorCode) {
+ return
+ }
+
+ // Otherwise, render show
+ return (
+
+
+ This is a server-side rendered catch-all page. It catches all requests made to
+ /shows/:id/any/path/can/go/here... and makes those parameters available in getInitialProps():
+
+ {params.map((param, index) => (
+
+ [{index}]: {param}
+
+
+ ))}
+
+ Refresh the page to see server-side rendering in action.
+
+ You can also try changing the URL to something random, such as /shows/
+ {show.id}/whatever/path/you/want
+
+ )
+}
+
+CatchAll.getInitialProps = async ({ res: req, query }) => {
+ // Get the params to render
+ const { params } = query
+
+ // Get the ID to render
+ const id = params[0]
+
+ // Get the data
+ const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await res.json()
+
+ // Set error code if show item could not be found
+ const errorCode = res.status > 200 ? res.status : false
+
+ return { errorCode, show: data, params }
+}
+
+export default CatchAll
diff --git a/demo/pages/shows/[id].js b/demo/pages/shows/[id].js
new file mode 100644
index 0000000000..43ecafd3e5
--- /dev/null
+++ b/demo/pages/shows/[id].js
@@ -0,0 +1,49 @@
+import Error from 'next/error'
+import Link from 'next/link'
+
+const Show = ({ errorCode, show }) => {
+ // If show item was not found, render 404 page
+ if (errorCode) {
+ return
+ }
+
+ // Otherwise, render show
+ return (
+
+
+ This page uses getInitialProps() to fetch the show with the ID provided in the URL: /shows/:id
+
+ Refresh the page to see server-side rendering in action.
+
+ You can also try changing the ID to any other number between 1-10000.
+
+ )
+}
+
+Show.getInitialProps = async ({ res: req, query }) => {
+ // Get the ID to render
+ const { id } = query
+
+ // Get the data
+ const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
+ const data = await res.json()
+
+ // Set error code if show item could not be found
+ const errorCode = res.status > 200 ? res.status : false
+
+ return { errorCode, show: data }
+}
+
+export default Show
diff --git a/demo/pages/static.js b/demo/pages/static.js
new file mode 100644
index 0000000000..a063432ae9
--- /dev/null
+++ b/demo/pages/static.js
@@ -0,0 +1,26 @@
+import Link from 'next/link'
+
+const Static = (props) => (
+
+
+ This page does not use getInitialProps.
+
+ It is a static page.
+
+ It is never server-side rendered.
+
+ It is served directly by Netlify's CDN.
+
+ The next-on-netlify npm package takes care of deciding
+ which pages to render server-side and which ones to serve directly via CDN.
+
+)
+
+export default Static
diff --git a/demo/pages/static/[id].js b/demo/pages/static/[id].js
new file mode 100644
index 0000000000..cc70b3136e
--- /dev/null
+++ b/demo/pages/static/[id].js
@@ -0,0 +1,32 @@
+import Link from 'next/link'
+
+const StaticWithID = (props) => (
+
+
+ This page does not use getInitialProps.
+
+ It is a static page.
+
+ It is never server-side rendered.
+
+ It is served directly by Netlify's CDN.
+
+
+ But it has a dynamic URL parameter: /static/:id.
+
+ Try changing the ID. It will always render this page, no matter what you put.
+
+ I am not sure what this is useful for.
+
+ But it's a feature of NextJS, so... I'm supporting it.
+