{"id":28496234,"url":"https://github.com/elitan/pgterra","last_synced_at":"2026-01-03T22:30:52.826Z","repository":{"id":297872552,"uuid":"997521892","full_name":"elitan/pgterra","owner":"elitan","description":"Declarative schema management for Postgres.","archived":false,"fork":false,"pushed_at":"2025-06-08T13:10:10.000Z","size":256,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-16T14:49:45.909Z","etag":null,"topics":["database","migrations","postgres","postgresql"],"latest_commit_sha":null,"homepage":"https://pgterra.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elitan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-06T17:10:44.000Z","updated_at":"2025-06-09T13:17:09.000Z","dependencies_parsed_at":"2025-06-08T03:23:23.157Z","dependency_job_id":"d5db18db-b15c-41e9-bac8-3ca2783a9e2d","html_url":"https://github.com/elitan/pgterra","commit_stats":null,"previous_names":["elitan/pgterra"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/elitan/pgterra","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fpgterra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fpgterra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fpgterra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fpgterra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elitan","download_url":"https://codeload.github.com/elitan/pgterra/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fpgterra/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260183005,"owners_count":22971195,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","migrations","postgres","postgresql"],"created_at":"2025-06-08T12:06:52.401Z","updated_at":"2025-12-28T12:05:58.520Z","avatar_url":"https://github.com/elitan.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/readme-hero.png\" alt=\"Terra - Declarative PostgreSQL schema management\" /\u003e\n  \u003cbr /\u003e\n  \u003cbr /\u003e\n  \u003ca href=\"https://github.com/elitan/terra/stargazers\"\u003e\n    \u003cimg alt=\"GitHub Stars\" src=\"https://img.shields.io/github/stars/elitan/terra?style=social\" /\u003e\n  \u003c/a\u003e\n    \u003ca href=\"https://discord.gg/PtePt2wx7R\"\u003e\n    \u003cimg alt=\"Discord\" src=\"https://img.shields.io/badge/Discord-Join%20Chat-5865F2?logo=discord\u0026logoColor=white\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://x.com/elitasson\"\u003e\n    \u003cimg alt=\"Twitter Follow\" src=\"https://img.shields.io/twitter/follow/elitasson?style=social\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cbr /\u003e\n\n# Terra\n\nDeclarative PostgreSQL schema management.\n\n## Install\n\n```bash\nnpm install -g pgterra\n```\n\n## Usage\n\n**1. Create schema.sql:**\n\n```sql\nCREATE TABLE users (\n  id SERIAL PRIMARY KEY,\n  email VARCHAR(255) NOT NULL UNIQUE\n);\n```\n\n**2. Preview changes:**\n\n```bash\npgterra plan\n```\n\n**3. Apply:**\n\n```bash\npgterra apply\n```\n\n**4. Update schema.sql:**\n\n```sql\nCREATE TABLE users (\n  id SERIAL PRIMARY KEY,\n  email VARCHAR(255) NOT NULL UNIQUE,\n  name VARCHAR(100) NOT NULL,        -- added\n  active BOOLEAN DEFAULT true        -- added\n);\n\nCREATE TABLE posts (                 -- added\n  id SERIAL PRIMARY KEY,\n  title VARCHAR(255) NOT NULL,\n  user_id INTEGER NOT NULL,\n  CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id)\n);\n\nCREATE INDEX idx_user_email ON users (LOWER(email));  -- added\n```\n\n**5. Terra generates the ALTER statements:**\n\n```bash\n$ pgterra plan\nALTER TABLE users ADD COLUMN name VARCHAR(100) NOT NULL\nALTER TABLE users ADD COLUMN active BOOLEAN DEFAULT true\nCREATE TABLE posts (...)\nCREATE INDEX idx_user_email ON users (LOWER(email))\n\n$ pgterra apply\n```\n\n## Configuration\n\nDatabase connection via `DATABASE_URL` or individual variables:\n\n```bash\nexport DATABASE_URL=\"postgres://user:password@localhost:5432/mydb\"\n```\n\nOr:\n\n```bash\nexport DB_HOST=localhost\nexport DB_PORT=5432\nexport DB_NAME=mydb\nexport DB_USER=postgres\nexport DB_PASSWORD=password\n```\n\n## What's supported\n\n**Tables \u0026 Columns:**\nAll PostgreSQL column types, default values, NOT NULL constraints\n\n**Functions \u0026 Procedures:**\nUser-defined functions and procedures with full PostgreSQL feature support\n\n**Triggers:**\nTable triggers with BEFORE/AFTER/INSTEAD OF timing\n\n**Sequences:**\nCustom sequences with configurable properties\n\n**Constraints:**\n```sql\n-- Primary keys\nid SERIAL PRIMARY KEY\n\n-- Foreign keys with actions\nCONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE\n\n-- Check constraints\nCONSTRAINT check_positive CHECK (quantity \u003e 0)\n\n-- Unique constraints\nemail VARCHAR(255) UNIQUE\nCONSTRAINT unique_email UNIQUE (email, domain)\n```\n\n**Indexes:**\n```sql\n-- Basic\nCREATE INDEX idx_email ON users (email);\n\n-- Partial\nCREATE INDEX idx_active_users ON users (email) WHERE active = true;\n\n-- Expression\nCREATE INDEX idx_lower_email ON users (LOWER(email));\n\n-- Concurrent (built automatically when safe)\n```\n\n**ENUM types:**\n```sql\nCREATE TYPE status AS ENUM ('pending', 'active', 'inactive');\n\nCREATE TABLE users (\n  id SERIAL PRIMARY KEY,\n  status status NOT NULL\n);\n```\n\n**Views:**\n```sql\nCREATE VIEW active_users AS\nSELECT id, email FROM users WHERE active = true;\n\nCREATE MATERIALIZED VIEW user_stats AS\nSELECT COUNT(*) as total FROM users;\n```\n\n**Functions:**\n```sql\nCREATE FUNCTION calculate_total(quantity INT, price DECIMAL)\nRETURNS DECIMAL\nAS $$\n  SELECT quantity * price\n$$\nLANGUAGE SQL IMMUTABLE;\n```\n\n**Procedures:**\n```sql\nCREATE PROCEDURE archive_old_posts(days_old INT)\nLANGUAGE SQL\nAS $$\n  DELETE FROM posts WHERE created_at \u003c NOW() - INTERVAL '1 day' * days_old;\n$$;\n```\n\n**Triggers:**\n```sql\n-- First create a trigger function\nCREATE FUNCTION update_modified_timestamp()\nRETURNS TRIGGER\nAS $$\n  BEGIN\n    NEW.modified_at = NOW();\n    RETURN NEW;\n  END;\n$$\nLANGUAGE plpgsql;\n\n-- Then create the trigger\nCREATE TRIGGER set_modified_timestamp\nBEFORE UPDATE ON users\nFOR EACH ROW\nEXECUTE FUNCTION update_modified_timestamp();\n```\n\n**Sequences:**\n```sql\nCREATE SEQUENCE custom_id_seq\nSTART 1000\nINCREMENT 1\nCACHE 20;\n```\n\n## Commands\n\n```bash\npgterra plan                    # Preview changes\npgterra plan -f custom.sql      # Use custom schema file\npgterra apply                   # Apply changes\npgterra apply -f custom.sql     # Apply from custom file\n```\n\n## Development\n\nRequires [Bun](https://bun.sh):\n\n```bash\ngit clone https://github.com/elitan/terra.git\ncd terra\nbun install\n\n# Start test database\ndocker compose up -d\n\n# Run tests\nexport DATABASE_URL=\"postgres://test_user:test_password@localhost:5487/sql_terraform_test\"\nbun test\n```\n\n## License\n\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felitan%2Fpgterra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felitan%2Fpgterra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felitan%2Fpgterra/lists"}