Dynamic routes not working when app is exported to static files
See original GitHub issueVerify canary release
- I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:37 PDT 2022; root:xnu-8020.121.3~4/RELEASE_ARM64_T6000
Binaries:
Node: 14.18.0
npm: 8.5.4
Yarn: 1.22.15
pnpm: 7.6.0
Relevant packages:
next: 12.2.5
eslint-config-next: 12.2.0
react: 18.2.0
react-dom: 18.2.0
What browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
next export
Describe the Bug
I have a site that is statically exported, and has dynamic routes.
This site works fine in dev mode. However if I build & export it, and then serve the static files, it has an isssue.
You can go to the site root and click on a link, which will take you to a dynamic post page like http://localhost:3000/post/1
and will work, but if you refresh the page (or visit directly) it 404s.
Why is this? Do dynamic routes, that need to access the router query object, not work when statically exported?
The dynamic route docs don’t mention any caveats to dynamic routes when used with static export.
The code:
Taking the next.js static example to start with, I edited it’s pages/post/[id].tsx
by removing the getStaticPaths
and getStaticProps
(as I don’t require build time static generation, and there are potentially millions of pages) and added clientside fetching on mount. I’m grabbing the router.query.id value and using it to fetch data:
⚡ Codesandbox here (which works fine as its running in dev, not exported served files)
import Head from 'next/head'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { GetPost } from '../../lib/postdata_api'
import { PostData } from '../../types/postdata'
const Post = () => {
const [postData, setPostData] = useState<null | PostData>(null)
const router = useRouter()
const id = router.query.id as string
const fetchData = async () => setPostData(await GetPost(id))
useEffect(() => {
if (!router.isReady) return
fetchData()
}, [router, router.isReady])
if (!postData) return 'Loading...'
return (
<main>
<Head>
<title>{postData.title}</title>
</Head>
<h1>{postData.title}</h1>
<p>{postData.body}</p>
<Link href="/">
<a>Go back to home</a>
</Link>
</main>
)
}
export default Post
Expected Behavior
I expected it to behave the as it does it dev. Meaning a user can:
- click a link on the root page
- view the dynamic post page eg
/post/1
- refresh / directly visit this post (without it 404ing)
Link to reproduction
https://codesandbox.io/s/hungry-wilson-t8rvlh?file=/pages/post/[id].tsx
To Reproduce
- Download the code sandbox or github repo
- run
npm run export && serve out
- visit
http://localhost:3000
- click a link to a post
- press refresh to see the 404
Issue Analytics
- State:
- Created a year ago
- Comments:11 (4 by maintainers)
As I said before, you could only find a
[id].html
under yourout/posts
(orbuild/posts
) folder.Only the Next.js server knows what
post/[id].html
means (and can translate[id]
to youruseRouter().id
). Other servers (Nginx, GitHub Pages, etc.) don’t know[id].html
has special meanings.This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.