KV access in a Sveltekit dev environment

Hi there. Appreciate the help in advance. I'm having the worst time trying to figure out if its possible to use a KV store in a dev environment. I'd like to use a full-on test KV where I can save keys and such. It seems everything that I've tried, platform.env on a server endpoint on my Sveltekit app is only available deployed in production. I'm using npx wrangler pages dev .svelte-kit/cloudflare once built, with
toml
kv_namespaces = [
{ binding = "test", id = "76n8s756fi7sd56fn", preview_id = "7sdtn6fi6s5dbf76s5ndf" },
]
toml
kv_namespaces = [
{ binding = "test", id = "76n8s756fi7sd56fn", preview_id = "7sdtn6fi6s5dbf76s5ndf" },
]
in my wrangler.toml. (random hash ids for example's sake) console logging platform.env is always undefined though the wrangler pages dev. I've done wrangler kv:namespace create test and used preview_id just as the docs say, but I just can never access platform Is it possible to have full KV functionality in a local dev environment? And if so, I don't understand how platform connects using Sveltekit.
6 Replies
Steved
Steved•16mo ago
@boggin unfortunately there doesn't seem to be a great solution for local development with full client+server sveltekit at the moment - or I've not found one. The best solution I've found so far is to use the following snippets that use miniflare (Cloudflare simulator) to simulate KV etc for local development. Firstly, in src/hooks.server.ts add a hook:
import { dev } from '$app/environment';
import type { Handle } from '@sveltejs/kit';

export const handle = (async ({ event, resolve }) => {
if (dev && !event.platform) {
const mf = await import('./lib/server/miniflare');
event.platform = await mf.setupPlatform();
}
return resolve(event);
}) satisfies Handle;
import { dev } from '$app/environment';
import type { Handle } from '@sveltejs/kit';

export const handle = (async ({ event, resolve }) => {
if (dev && !event.platform) {
const mf = await import('./lib/server/miniflare');
event.platform = await mf.setupPlatform();
}
return resolve(event);
}) satisfies Handle;
This dynamically loads the miniflare stuff, and should be optimised away in a production build. Then a new miniflare.ts with the emulations (see attachment). Add some packages to your package.json:
"@miniflare/cache": "^2.14.0",
"@miniflare/d1": "^2.14.0",
"@miniflare/durable-objects": "^2.14.0",
"@miniflare/kv": "^2.14.0",
"@miniflare/r2": "^2.14.0",
"@miniflare/storage-file": "^2.14.0",
"@miniflare/storage-memory": "^2.14.0",
"@miniflare/cache": "^2.14.0",
"@miniflare/d1": "^2.14.0",
"@miniflare/durable-objects": "^2.14.0",
"@miniflare/kv": "^2.14.0",
"@miniflare/r2": "^2.14.0",
"@miniflare/storage-file": "^2.14.0",
"@miniflare/storage-memory": "^2.14.0",
Then my 'dev' script is just to run vite:
"dev": "vite dev --host",
"dev": "vite dev --host",
Steved
Steved•16mo ago
The miniflare.ts file reads the app.d.ts file to work out what to add to the platform variable, so you need to make sure that is setup too, for example:
declare global {
namespace App {
interface Platform {
env?: {
COUNTER: KVNamespace;
DATABASE: D1Database;
};
context: {
waitUntil(promise: Promise<unknown>): void;
};
caches: CacheStorage & { default: Cache };
cf?: IncomingRequestCfProperties;
}
}
}

export {};
declare global {
namespace App {
interface Platform {
env?: {
COUNTER: KVNamespace;
DATABASE: D1Database;
};
context: {
waitUntil(promise: Promise<unknown>): void;
};
caches: CacheStorage & { default: Cache };
cf?: IncomingRequestCfProperties;
}
}
}

export {};
The critical bit is inside the env object.
boggin
boggin•16mo ago
Very interesting solution. I tried dabbling in miniflare, but it seems that CF has integrated it in wrangler enough and I couldnt get anywhere with the docs. Maybe I'll try your solution out one day thank you. In the meantine, I simply setup a JS Pojo to store strings. Didnt wanna deal with REdis or anything so its all runtime. Thank you
divby0
divby0•13mo ago
@steveda and @boggin. do you guys have got otherwise working local environment? I have 4-5 seconds until vite build is finished and the wrangler has updated. After that I manually have to refresh. I'd so much like to keep that instant hotreload from svelte-kit dev without wrangler....
Steved
Steved•13mo ago
I do have a setup which works locally (a variant of the above snippets), which works well for me in Sveltekit. The great benefit is that vite-based hot reloading just works, and I only have one setup running - there's none of this having wrangler watch the output of the output directory of the sveltekit build. To be fair, my current setup isn't very demanding on CF, but does use KV and D1. I've even added a subset of the cf object properties (country etc.). The latest version of the script now 'parses' the required toml file, and puts the D1 database in the same location wrangler expects it, so that you can use wrangler d1 migrations [list|apply] locally.
divby0
divby0•13mo ago
I had the parallel wrangler + vite build before 🙂 I researched a bunch yesterday and finally figured out how to have the super fast hotreload and still use cf bindings: https://github.com/sveltejs/kit/issues/4292#issuecomment-1732643660. Just if anyone reads this later, this is probably the best solution with near to now drawbacks
GitHub
Platform context fallbacks · Issue #4292 · sveltejs/kit
Describe the problem When developing with svelte-kit dev, the event.platform object is always empty, with no great way to mock it. When building using an adapter like Cloudflare Workers, event.plat...
Want results from more Discord servers?
Add your server