State
Add durable key-value storage to your workers with simple get/set/delete operations.
State
Ploy State provides a durable key-value store backed by SQLite. Unlike cache, state has no expiry -- data persists until you explicitly delete it. This makes it ideal for user preferences, feature flags, counters, and any data that should survive restarts.
Configuration
Add a state binding in your ploy.yaml:
kind: dynamic
build: pnpm build
out: dist
state:
STATE: defaultThe key (STATE) is the binding name available in your worker's env. The value (default) is the state store identifier.
Run ploy types to generate TypeScript types:
import type { StateBinding } from "@meetploy/types";
export interface Env {
STATE: StateBinding;
}Basic Example
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === "/set") {
await env.STATE.set("greeting", "hello world");
return Response.json({ success: true });
}
if (url.pathname === "/get") {
const value = await env.STATE.get("greeting");
return Response.json({ value });
}
if (url.pathname === "/delete") {
await env.STATE.delete("greeting");
return Response.json({ success: true });
}
return new Response("State Worker");
},
} satisfies Ploy;API Methods
get(key) - Get a Value
Returns the stored value or null if the key doesn't exist.
const value = await env.STATE.get("my-key");
// value is string | nullset(key, value) - Set a Value
Stores a string value. Overwrites any existing value for the same key. Data persists until explicitly deleted.
await env.STATE.set("username", "alice");delete(key) - Delete a Value
Removes a key from the state store.
await env.STATE.delete("username");All state values are strings. Use JSON.stringify() and JSON.parse() to
store structured data.
Common Patterns
Storing JSON Data
// Set
const user = { name: "Alice", role: "admin" };
await env.STATE.set("user:123", JSON.stringify(user));
// Get
const raw = await env.STATE.get("user:123");
const user = raw ? JSON.parse(raw) : null;Feature Flags
async function isFeatureEnabled(
env: PloyEnv,
feature: string,
): Promise<boolean> {
const value = await env.STATE.get(`feature:${feature}`);
return value === "true";
}
// Enable a feature
await env.STATE.set("feature:dark-mode", "true");
// Check the feature
const enabled = await isFeatureEnabled(env, "dark-mode");Persistent Counters
async function incrementCounter(env: PloyEnv, name: string): Promise<number> {
const current = await env.STATE.get(`counter:${name}`);
const newCount = current ? parseInt(current) + 1 : 1;
await env.STATE.set(`counter:${name}`, String(newCount));
return newCount;
}User Preferences
async function getUserPreferences(env: PloyEnv, userId: string) {
const raw = await env.STATE.get(`prefs:${userId}`);
return raw ? JSON.parse(raw) : { theme: "light", language: "en" };
}
async function setUserPreferences(
env: PloyEnv,
userId: string,
prefs: Record<string, string>,
) {
await env.STATE.set(`prefs:${userId}`, JSON.stringify(prefs));
}Multiple State Bindings
You can configure multiple state stores for different use cases:
state:
STATE: default
USER_STATE: users// General state
await env.STATE.set("config", value);
// User-specific state
await env.USER_STATE.set("user:abc", userData);Next Steps
How is this guide?
Last updated on