@netlify/dev: site base directory resolved against projectRoot, breaking dev when the site lives in a subdirectory
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 26
- Forks
- 21
- Avg merge
- 22h 38m
- Merged PRs (30d)
- 13
Description
Summary
When a site lives in a subdirectory of the repository (e.g. www/) and the checkout is linked to a Netlify site whose Base directory is set to that same subdirectory, NetlifyDev.start() throws and the dev server exits before becoming ready.
The base directory ends up applied twice: <repo>/www + www → <repo>/www/www.
When resolving config file <repo>/www/netlify.toml:
Base directory does not exist: <repo>/www/www
Cause
@netlify/vite-plugin constructs NetlifyDev with the Vite project root:
const netlifyDev = new NetlifyDev({
...,
projectRoot: viteDevServer.config.root,
})
@netlify/dev then passes that same value through as repositoryRoot:
async getConfig() {
const configFilePath = path.resolve(this.#projectRoot, 'netlify.toml')
const config = await resolveConfig({
config: configFileExists ? configFilePath : undefined,
offline: !this.#siteID,
repositoryRoot: this.#projectRoot, // <-- Vite project root, not the repository root
siteId: this.#siteID,
})
}
Because a siteId is present, offline is false, so @netlify/config fetches the site and maps build_settings.base into defaultConfig.build.base (packages/config/lib/api/build_settings.js — "Netlify UI build settings are used as default configuration values"). getBase() then resolves that value against repositoryRoot, and getBuildDir() throws because the resulting directory does not exist.
Netlify documents the base directory as relative to the repository root. When the site lives in a subdirectory, projectRoot is already that base directory, so resolving the setting against it applies the same path segment a second time.
Reproduce
- A repo whose site lives in
www/— its ownpackage.jsonandnetlify.toml, and nobasekey in that toml. - A Netlify site with Base directory set to
www(correct, and required for the build to work). netlify linknpm run dev(Astro +@astrojs/netlify)
The dev server exits printing only Dev server process exited before becoming ready. — the real error is in .astro/dev.log, since astro dev daemonizes.
Removing the siteId from www/.netlify/state.json makes it work again, because offline: !this.#siteID becomes true and no build settings are fetched. That is what makes this look intermittent: it is latent until the checkout is linked.
Expected
Local dev should resolve the base directory against the repository root — or ignore it when projectRoot already is the base directory — so that a configuration which builds correctly on Netlify also runs locally.
Workaround
Set NETLIFY_DEV=true so @netlify/vite-plugin returns no plugins and nothing resolves the config:
function netlify(options = {}) {
if (process.env.NETLIFY_DEV) return []
This costs the local emulation (image CDN proxy, edge function sandbox, environment variable injection).
Notes
Deploys are unaffected: getSiteInfo short-circuits on mode === 'buildbot', since the buildbot passes the settings itself. This is local emulation only.
Versions
| package | version |
|---|---|
@netlify/dev |
4.18.11 |
@netlify/vite-plugin |
2.12.9 |
@netlify/config |
25.1.1 |
@astrojs/netlify |
8.1.3 |
astro |
7.1.6 |
| node | 24.18.0 |
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the NetlifyDev.getConfig() path in @netlify/dev and the Netlify Vite plugin construction of NetlifyDev, then inspect packages/config/lib/api/build_settings.js. Reproduce with a linked site whose base directory is www and a projectRoot of www. Done means local dev starts for this layout without resolving www twice while retaining local emulation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript, vite
- Domain
- build-system, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100