Skip to article
NEXUSDocs
Documentation/Administration
Configuration guide

Terraform Provider

Manage Nexus application configuration as code with the official Nexus Terraform provider

Before you begin

Availability depends on your school's enabled tools, provider setup, and account permissions. These settings are managed in the web workspace. A class policy may restrict a feature described here. Some options require a separately licensed feature. The presence of a guide does not unlock that feature.

The Nexus Terraform provider manages the configuration inside a running Nexus deployment: LLM providers, connectors and their credentials, document sets, agents, actions, MCP servers, user groups, API keys, and workspace settings.

Everything you would otherwise click through in the Admin Panel becomes a version-controlled .tf file that you can review, diff, and apply from CI.

onyx-dot-app/onyx on the Terraform Registry#

The registry holds the full reference: every resource, every attribute, and the import syntax. This page covers what the provider is for and how to get started.

Two different Terraform surfaces#

Nexus has two separate Terraform offerings. They solve different problems and are used at different times.

Terraform modulesTerraform provider (this page)
ManagesThe infrastructure Nexus runs onThe configuration inside Nexus
CreatesVPC, EKS, RDS, ElastiCache, S3, OpenSearch, WAFLLM providers, connectors, document sets, agents, groups
Distributed asModules in the onyx repo you copy and adaptA published provider you declare in required_providers
Talks toAWSThe Nexus admin API of a deployment that is already running
UsedBefore Nexus existsAfter Nexus is reachable

The two compose. Provision infrastructure with the modules, install Nexus with the Helm chart, then configure the deployment with this provider. You can run them from the same root module, but they are independent. the provider works against any reachable Nexus deployment, including a managed deployment, regardless of how it was deployed.

Requirements#

  • Terraform 1.5 or later. Write-only secret arguments. the recommended way to keep credentials out of state. need 1.11 or later, and an older CLI rejects a configuration that uses one.

  • A reachable Nexus deployment. The provider is an API client; it does not install or upgrade Nexus.

  • An API key in the Admin group. An API key's access comes from its group membership, so a key with no group cannot reach the admin endpoints the provider uses.

Get an API key#

Create a key in the Admin Panel under API Keys. see Service Accounts , and give it admin access. An unrestricted Personal Access Token created by an admin also works.

API keys authenticate the same way whatever the deployment's human AUTH_TYPE is (basic, OIDC, SAML, or cloud), and credentials must belong to the workspace that owns the resource.

This first key is a chicken-and-egg problem: it has to exist before Terraform can run. Either leave it unmanaged, or terraform import it afterwards. On import its api_key attribute stays null, because Nexus only ever returns the key material at creation.

For a scripted setup, examples/bootstrap/mint_api_key.sh runs the whole sequence: register, log in, resolve the Admin group, mint the key.

The script requires an admin email and password rather than defaulting them. On a deployment with no users it registers that account, and the first user to register becomes an admin. so a defaulted password would quietly create a known-password administrator on any reachable deployment.

Configure the provider#

terraform {
required_providers {
  onyx = {
    source  = "onyx-dot-app/onyx"
    version = "~> 0.2"
  }
}
}

provider "onyx" {
endpoint = "https://onyx.example.com" # or ONYX_SERVER_URL
api_key  = var.onyx_api_key           # or ONYX_API_KEY
}

Nexus server origin, for example https://school.narb.cc or http://localhost:3000. Also read from ONYX_SERVER_URL.

An API key (on_...) in the seeded Admin group, or an unrestricted personal access token (onyx_pat_...). Also read from ONYX_API_KEY.

Path prefix the API is served under. The default matches the web proxy. Set it to "" when you point the provider directly at the backend, for example http://localhost:8080. Also read from ONYX_API_PREFIX.

Supply api_key from the ONYX_API_KEY environment variable rather than a .tf file. Provider configuration is the one place Terraform never writes to state, so an environment variable keeps the key out of both your repository and your state file.

What you can manage#

Each entry links to its full schema on the Terraform Registry.

Resources#

ResourceManages
onyx_llm_providerAn LLM provider and the model list it exposes
onyx_llm_provider_defaultThe deployment default and vision models. a singleton
onyx_embedding_providerCloud embedding provider credentials
onyx_credentialConnector credentials
onyx_connectorConnector definitions and their sync schedule
onyx_cc_pairThe connector-credential pair that starts indexing and carries access control
onyx_document_setDocument sets built from connector-credential pairs
onyx_personaAgents, including their prompts, document sets, and actions
onyx_custom_toolCustom actions defined from an OpenAPI schema
onyx_mcp_serverMCP servers Nexus connects to
onyx_user_groupUser groups: roster, managers, and permission grants
onyx_api_keyAPI keys
onyx_settingsWorkspace settings. a singleton, partially managed

Data sources#

Data sourceReads
onyx_llm_providersConfigured LLM providers and the current defaults
onyx_embedding_providersConfigured embedding providers
onyx_connectorsConfigured connectors
onyx_settingsCurrent workspace settings, including the license tier

Every resource supports terraform import, so you can bring a deployment configured by hand under Terraform without recreating anything. The import id is on each resource's registry page.

A worked example#

This wires a chat model to an indexed site and an agent that answers from it. It is the shape most configurations take: a provider, a credential, a connector, the pair that links them, a document set, and an agent.

resource "onyx_llm_provider" "openai" {
name          = "openai"
provider_type = "openai"

# Write-only: the key never reaches the state file. See below.
api_key_wo         = var.openai_api_key
api_key_wo_version = 1

# The complete set of enabled models: anything omitted is removed on apply.
model_configurations = [
  { name = "gpt-5" },
  { name = "gpt-5-mini" },
]
}

# Referencing the provider id also orders destroys correctly: the default is
# released before the provider holding it is deleted.
resource "onyx_llm_provider_default" "this" {
provider_id = onyx_llm_provider.openai.id
model_name  = "gpt-5"
}

# The web connector reads public pages, so its credential holds no secret.
resource "onyx_credential" "web" {
source          = "web"
name            = "public-web"
credential_json = jsonencode({})
}

resource "onyx_connector" "docs" {
name       = "docs-site"
source     = "web"
input_type = "load_state"

# Re-index once a day.
refresh_freq = 24 * 60 * 60

connector_specific_config = jsonencode({
  base_url           = var.docs_base_url
  web_connector_type = "recursive"
})
}

# The pair is the object that indexes. It also carries the access control for
# the documents it produces.
resource "onyx_cc_pair" "docs" {
name          = "docs-site"
connector_id  = onyx_connector.docs.id
credential_id = onyx_credential.web.id
access_type   = "public"
}

resource "onyx_document_set" "docs" {
name        = "docs"
description = "Public product documentation"
cc_pair_ids = [onyx_cc_pair.docs.id]
}

resource "onyx_persona" "docs" {
name        = "Docs"
description = "Answers product questions from the documentation"

system_prompt = <<-EOT
  You answer questions from the product documentation.
  If the documentation does not cover the question, say so.
EOT

document_set_ids = [onyx_document_set.docs.id]
}

A complete, runnable version of this configuration lives in examples/bootstrap/.

Keeping secrets out of state#

Every secret the provider accepts comes in two forms. The plain attribute is stored in Terraform state, where anyone who can read the state file can read the secret. The _wo twin is a write-only argument: Terraform strips the value from both the plan and the state, so it exists only in your configuration.

Prefer the twin. Set one or the other, never both.

ResourceStored attributeWrite-only twin
onyx_llm_providerapi_key, custom_configapi_key_wo, custom_config_wo
onyx_embedding_providerapi_keyapi_key_wo
onyx_credentialcredential_jsoncredential_json_wo
onyx_mcp_serverapi_token, admin_credentialsapi_token_wo, admin_credentials_wo
onyx_custom_toolcustom_headerscustom_headers_wo

Rotating a write-only secret#

A value Terraform never stores is a value it cannot diff, so changing api_key_wo on its own plans nothing at all. Each twin has a _wo_version counter for exactly this: raise it, and the resulting diff makes the next apply send the current secret.

resource "onyx_llm_provider" "openai" {
name          = "openai"
provider_type = "openai"

api_key_wo         = var.openai_api_key
api_key_wo_version = 2 # was 1 — bump after rotating the key

model_configurations = [{ name = "gpt-5-mini" }]
}

Do not derive the counter from the secret. md5(var.token) and similar. Unlike the secret, the counter is kept in state.

Two attributes cannot have a write-only twin. onyx_api_key.api_key is minted by Nexus rather than supplied by you, so Terraform can only hand it back through state. treat the state file as holding it. onyx_mcp_server.auth_template_headers is computed by Nexus, and Terraform does not allow an argument to be both computed and write-only.

Regardless of which form you use, encrypt your Terraform state and restrict who can read it. Several resources hold credentials for systems well outside Nexus.

Enterprise Edition#

Most of the provider works on Community Edition. These parts need Enterprise Edition:

  • onyx_user_group. the routes live in the Enterprise application and answer 404 on Community Edition.

  • users and groups on onyx_document_set and onyx_persona. Community Edition rejects a private set or agent.

Enterprise Edition Feature

These features require an Enterprise plan. View plans or contact sales to learn more.

Things the API cannot express#

A few behaviours come from the Nexus API rather than the provider, and are worth knowing before you rely on them:

  • Secret drift is invisible. The API masks secrets on read, so rotating one in the Admin Panel does not show up in terraform plan. The configured value is authoritative and is re-asserted on the next apply.

  • onyx_settings and onyx_llm_provider_default do not really delete. Nexus has no reset API for either, so destroy removes them from state with a warning and leaves the live values alone.

  • model_configurations is the list of record. A model left out of it is removed from the provider server-side.

  • Deleting an agent leaves a tombstone. The name stays taken, and a later create under that name revives the same agent id rather than making a new one.

  • Deleting a custom action detaches it from every agent that uses it, including agents Terraform does not manage, with no error and no warning.

The provider README carries the full list, and each resource's registry page repeats the ones that apply to it.

Source and releases#

Pin the provider version in required_providers and let Terraform's lock file pick up the checksums, the same as any other provider. The registry page always shows the current release.

NEXUS

Nexus helps students think, practice, and learn, with teachers guiding AI use.

[ Support ]

[ NARB TECHNOLOGY INC. ]

Nexus is a school AI platform by narb Technology Inc. · 16192 Coastal Hwy, Lewes, DE 19958

© 2026 narb Technology Inc.

Nexus

Nexus helps schools make room for questions, practice, and reflection — with teacher guidance in view.

[ Contact us through e-mail ]

© 2026 narb Technology Inc.

NEXUS

Nexus helps students think, practice, and learn, with teachers guiding AI use.

[ Support ]

[ NARB TECHNOLOGY INC. ]

Nexus is a school AI platform by narb Technology Inc.

© 2026 narb Technology Inc.