Svelte / Advanced: rendering, resources and release evidence / Lesson 17
Adapters, environment and deployment ownership
Match Kit 3 build artifacts to runtime capabilities and keep public/private configuration and shared state explicitly owned.
On this page
Lesson goals
- Explain adapter output and why static hosting is not every server capability.
- Distinguish Kit 3 declared environment variables from older prefix/static-module conventions.
An adapter targets a deployment contract
A Kit adapter transforms the application build for a particular hosting/runtime model. It does not guarantee that every host supports the same filesystem, request duration, source library or cache persistence. Static prerendered output cannot replace request-time actions and authenticated server loads without redesigning those features. An automatic adapter can recognize supported environments, but that is not universal infrastructure provisioning. Review route options, required server work and asset paths with the chosen adapter version. Keep source connection ownership and long-lived tasks aligned with the actual process/function lifetime rather than assuming a development server represents production behavior.
Use the selected Kit 3 declaration and visibility model
Current Kit 3 documentation defines variables in src/env.js through defineEnvVars and exposes declared values through $app/env/private or public. Values are private unless deliberately declared public, and static:true binds a value into build output rather than the default dynamic behavior. This differs from older $env/static and $env/dynamic module conventions and PUBLIC_ prefix assumptions. The JSON is a design classification, not an actual env declaration or secret. Never mark a credential public merely to make it convenient for a browser component. A private module can still leak a value if load or an action returns it.
{"selectedKitMajor":3,"declaration":"src/env.js-defined-variables","privateAccess":"$app/env/private","publicAccess":"$app/env/public","defaultVisibility":"private","staticTrue":"build-bound","credentialValue":"not-contained"}
This record contains no credential and is not a real defineEnvVars configuration. No environment is loaded.
Keep configuration and module aliases with the build
Kit 3 moves project configuration into the sveltekit Vite plugin rather than the former svelte.config.js arrangement. The #lib alias uses declared package subpath imports and appropriate file extensions instead of assuming $lib is automatically generated. These build inputs must travel with lockfile and compiled output when promoting or rolling back a release. A generated client bundle and prerendered content can capture public values earlier than runtime, so verify the actual binding path. Do not run upgrade commands, install adapters or modify a configured deployment during course authoring; this material records the contract, not a deployed result.
Validate a bounded option without reading real environment
The local parser supplies ten for an omitted limit, accepts a complete positive integer up to fifty and rejects invalid supplied text. The thresholds are synthetic, not operational tuning recommendations. It never reads process.env, a secret or a file. A real declaration/schema must preserve the intended distinction between absence and deployment error and report setting names safely. This test does not prove that Kit loaded a declaration, that a static value was compiled correctly or that the adapter exposes runtime variables as expected. Those are separate integration boundaries requiring the exact selected toolchain.
function option(text){
if(text===undefined)return 10;
if(typeof text!=="string" || !/^[1-9][0-9]*$/.test(text))throw new Error("INVALID_LIMIT");
const n=Number(text);if(!Number.isSafeInteger(n)||n>50)throw new Error("INVALID_LIMIT");return n;
}
console.assert(option(undefined)===10 && option("20")===20);
let rejected=false;try{option("20rows");}catch{rejected=true;}console.assert(rejected);
Omission defaults and invalid text rejects under the declared rule. No Kit env module or runtime is accessed.
Verify sharing, cleanup and rollback instead of assuming durability
Multiple workers do not automatically share module variables, replay maps, sessions or local files. An ephemeral filesystem is not durable shared upload storage. Define cache/session/backing-store behavior and drain/cleanup ownership for the chosen platform, including uncertain writes at shutdown. Test health and readiness under the intended contract without exposing secrets. This course parses the classification and runs only the option parser; it does not build, adapt, deploy, start a process, open a source pool or operate cloud services. Real verification must be separately authorized and record exact packages, artifacts and remaining limitations rather than a generic successful-deployment claim.
Common errors and fixes
A private credential is declared public for convenience
- Why it happens
- Visibility configuration was used as a shortcut across the server boundary.
- How to fix it
- Keep credentials private and project only approved client values.
- Prevent it next time
- Review load/action results and generated client output.
An old $lib assumption breaks Kit 3 imports
- Why it happens
- The migration omitted declared #lib subpath imports and extensions.
- How to fix it
- Update aliases under the selected package/build contract.
- Prevent it next time
- Validate runtime and compiler resolution with retained fixtures.
Local worker state is called shared durable storage
- Why it happens
- Instance and persistence lifetimes were not reviewed.
- How to fix it
- Use a reviewed shared storage protocol where required.
- Prevent it next time
- Test replacement and multi-instance assumptions separately.
Check your understanding
1. Does a private environment import prevent every possible secret leak?
Show worked solution
No. It protects the import boundary under the framework, but code can still return the value from load, render it or put it in an action result. Review every output audience and log field. Keep private source capabilities behind the server boundary and return only deliberate public or principal-scoped models.
2. Why record static versus dynamic binding with a promoted artifact?
Show worked solution
A build-bound value may already be embedded in client or prerendered bytes, while runtime values depend on the selected adapter/startup contract. Changing a later environment does not necessarily rewrite earlier artifacts. Verify the intended binding and rebuild or use the supported runtime design deliberately.
Key takeaways
- Adapter output, environment visibility and lifetime are application contracts.
- A local parser provides no hosting or persistence certification.