Bring an existing Terraform project into ops0 to get deployment history, approval gates, policy checks, and team collaboration — without changing any of your Terraform code.
Scenario
Your team has been running Terraform locally for the past year. You have a production VPC project in a GitHub repository and you want to move it into ops0 for deployment history, approval gates, policy checks, and team collaboration — without touching any of your existing Terraform code.
Two Import Paths
Path
When to Use
From GitHub
Code is already in a GitHub repo
Upload / Paste
Code is local, no Git yet
Part 1: Import from GitHub
Prerequisites
✓GitHub integration configured in Settings → Integrations → GitHub
✓Repository contains valid Terraform (.tf files)
✓Cloud integration with deploy permissions for the target account
Create the Project and Sync from GitHub
1Go to IaC → New Project
2Enter a project name — match your existing project name for clarity
3Select Terraform (or OpenTofu if you were using that)
4Click Create
5In the project editor, click GitHub in the toolbar
6Select your repository and branch (e.g. main)
7Set the path if your Terraform is in a subdirectory (e.g. infrastructure/vpc/)
8Click Sync from GitHub — ops0 pulls all .tf files into the editor
9Verify the files appear correctly in the file explorer
Part 2: Configure the State Backend
Point ops0 to your existing state file
If you configure a new state backend path, Terraform will treat all your existing resources as new and try to create them again. You must use the exact same bucket, key, and region as your current backend.
1Go to Project Settings → Backend
2Select the same backend type you're currently using (S3, GCS, Azure Blob, etc.)
3Enter the exact same bucket, key, and region as your existing backend.tf
4Select the cloud integration with the same permissions your team was using locally
Enter those exact values in ops0. ops0 will use the existing state file — Terraform sees the existing resources as already tracked and makes no changes.
Part 3: Verify with a Plan
Run a plan to confirm ops0 is reading your state correctly.
1Click Deploy → Run Plan
2Expected result: 0 changes — Terraform reads the existing state and finds everything matches
3If the plan shows unexpected creates: the state path is wrong or the credentials have different scope — double-check the backend configuration
A clean 0-change plan means ops0 is now managing your existing infrastructure correctly. Any differences shown are real drift between your code and the actual resource configuration.
Part 4: Enable Team Features
Now that the project is imported, enable the ops0 features that weren't available before.
Add team members
1Project → Collaborators → Add → select teammates → assign Editor or Approver role
Enable approval gates
1Project Settings → enable Require Approval → designate an approver
Add policies
1Settings → Policies → create or attach policies to the project → every deploy is now checked before apply
Connect GitHub sync for PR workflows
1GitHub button → set to main branch → changes pushed via PR now sync back into ops0 automatically
Verification
Confirm the import is complete and working:
Plan shows 0 changes after import
Project card shows correct file count and last-modified time
Team members can see the project in their IaC list
A test deployment (no code changes) completes successfully
Troubleshooting
Plan shows all resources being created
The state backend path is wrong — ops0 is pointing to an empty or new state file. Fix the bucket, key, and region in Project Settings → Backend, then retry the plan.
Provider not configured error
Your provider.tf contains profile = "default" or similar local-only config. Remove it or replace with IAM role-based auth — ops0 uses the connected cloud integration, not local AWS profiles.
Syntax errors after GitHub sync
The files synced correctly but contain Terraform version-specific syntax. Check the required_version constraint in your code and ensure it matches ops0 (Terraform 1.5+).
State lock error
Another deployment is running, or a previous run left the lock held. If using S3 with DynamoDB locking, delete the lock item manually in DynamoDB, or wait for the other process to complete before retrying.