Vite
Using OpenPolicy with the Vite plugin
The @openpolicy/vite package provides a Vite plugin that compiles your policy config automatically — at build time and in dev mode with hot-reload.
Installation
bun add -D @openpolicy/vite @openpolicy/sdkCreate your config
Create an openpolicy.ts at the root of your project using defineConfig() from @openpolicy/sdk:
// openpolicy.ts
import { defineConfig } from "@openpolicy/sdk";
export default defineConfig({
company: {
name: "Acme Inc.",
legalName: "Acme Corporation",
address: "123 Main St, Springfield, USA",
contact: "privacy@acme.com",
},
privacy: {
effectiveDate: "2026-01-01",
dataCollected: {
"Account Information": ["Name", "Email address"],
"Usage Data": ["Pages visited", "Browser type", "IP address"],
},
legalBasis: "Legitimate interests and consent",
retention: { "Account data": "Until account deletion" },
cookies: { essential: true, analytics: false, marketing: false },
thirdParties: [],
userRights: ["access", "erasure"],
jurisdictions: ["us", "eu"],
},
terms: {
effectiveDate: "2026-01-01",
acceptance: { methods: ["using the service", "creating an account"] },
governingLaw: { jurisdiction: "Delaware, USA" },
},
});See the openpolicy.ts reference → for all available fields.
Setup
Add openPolicy() to the plugins array in your Vite config. When no options are passed, the plugin looks for openpolicy.ts by default:
// vite.config.ts
import { defineConfig } from "vite";
import { openPolicy } from "@openpolicy/vite";
export default defineConfig({
plugins: [openPolicy()],
});To customize the output location or formats, pass options explicitly:
openPolicy({
formats: ["markdown", "html"],
outDir: "public/policies",
})Options
| Option | Type | Default | Description |
|---|---|---|---|
configPath | string | "openpolicy.ts" | Path to the unified policy config file, relative to the Vite root. |
formats | OutputFormat[] | ["markdown"] | Output formats: "markdown" | "html" | "pdf" |
outDir | string | "public/policies" | Output directory, relative to the Vite root |
Use { config: "legal.config.ts", type: "terms" } to override explicitly.
Unified config
When the plugin loads a file that exports a defineConfig() result, it automatically compiles all sections present — privacy, terms, and cookie — in a single pass. You don't need to list them separately:
// generates privacy-policy.md, terms-of-service.md, and cookie-policy.md
openPolicy({ formats: ["markdown"], outDir: "public/policies" })To use a different filename, pass configPath:
openPolicy({
configPath: "my-policies.ts",
formats: ["markdown", "html"],
outDir: "public/policies",
})Scaffold
If a config file doesn't exist when Vite starts, the plugin creates a starter config at that path with placeholder content. Edit the file and save — the dev server picks up the changes automatically.
Build mode
During vite build, the plugin writes all policy files to outDir before Vite processes other assets. Files in public/ are copied to dist/ automatically by Vite.
Dev mode
During vite dev, the plugin:
- Compiles all configs on startup
- Watches every config file for changes (using Vite's built-in Chokidar watcher)
- Regenerates the affected policy file on every save without restarting the dev server
Errors during regeneration are logged to the console but don't crash the dev server.
Output
Output filenames are determined by the policy type:
| Policy type | Output filenames |
|---|---|
"privacy" | privacy-policy.md, privacy-policy.html, privacy-policy.pdf |
"terms" | terms-of-service.md, terms-of-service.html, terms-of-service.pdf |
"cookie" | cookie-policy.md, cookie-policy.html, cookie-policy.pdf |
Astro
For Astro projects, use the dedicated @openpolicy/astro integration instead. It wraps this Vite plugin and plugs into Astro's first-class integration API.