Skip to content

sqldoc

SQL-first development

A pluggable compiler pipeline for SQL schemas. Tags in comments drive code generation, migrations, and custom plugins. Your .sql files are the source of truth.

See It in Action

Write standard SQL with tags in comments:

INPUT SQL
sql
-- @import '@sqldoc/ns-audit'
-- @import '@sqldoc/ns-codegen'
-- @import '@sqldoc/ns-docs'
-- @import '@sqldoc/ns-rls'
-- @import '@sqldoc/ns-validate'

-- @docs.description('User accounts for the application')
-- @audit(on: [insert])
-- @rls
-- @rls.policy(for: ALL, to: authenticated, using: 'user_id = current_setting(''app.user_id'')::int')
CREATE TABLE users (
  -- @codegen.rename('id')
  user_id SERIAL PRIMARY KEY,

  -- @validate.pattern('^.+@.+\..+$')
  email VARCHAR(100) NOT NULL,

  -- @audit.redact(strategy: omit)
  password_hash TEXT NOT NULL
);
COMPILED OUTPUT
sql
CREATE TABLE users (
  user_id SERIAL PRIMARY KEY,

  email VARCHAR(100) NOT NULL,

  password_hash TEXT NOT NULL
);

-- Generated by sqldoc
-- sqldoc: @audit(on: [insert])
CREATE TABLE IF NOT EXISTS "users_audit_log" (
  id BIGSERIAL PRIMARY KEY,
  table_name TEXT NOT NULL,
  operation TEXT NOT NULL,
  old_data JSONB,
  new_data JSONB,
  changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE OR REPLACE FUNCTION "users_audit_fn"() RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO "users_audit_log" (table_name, operation, old_data, new_data, changed_at)
  VALUES (TG_TABLE_NAME, TG_OP, CASE WHEN TG_OP = 'INSERT' THEN NULL ELSE row_to_json(OLD) END, row_to_json(NEW), now());
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "users_audit_trigger"
  AFTER INSERT ON "users"
  FOR EACH ROW EXECUTE FUNCTION "users_audit_fn"();
-- sqldoc: @rls
ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;
-- sqldoc: @rls.policy(for: ALL, to: authenticated, using: 'user_id = current_setting(''app.user_id'')::int')
CREATE POLICY "users_authenticated_all" ON "users"
  FOR ALL
  TO authenticated
  USING (user_id = current_setting();
-- sqldoc: @validate.pattern('^.+@.+\..+$')
ALTER TABLE "users" ADD CONSTRAINT "users_email_pattern" CHECK ("email" ~ '^.+@.+\..+$');

Tags compile to correct SQL for your dialect. The original SQL stays unchanged — tags are comments.

Namespace Plugins

10 plugins covering audit trails, security, validation, documentation, and more.

Code Generation Templates

0 templates across 0 languages. Generate typed code from your SQL schema.