Skip to main content

Archive services and links New

🚀 Early release

Archiving is in early release and may not be available in your organization yet. If you'd like to try it or want to know more, reach out to us and we'll get you set up.

Archiving is a soft delete for services and links. An archived instance stops showing up in your service lists and its link parameters are removed, but the instance and all its attributes stay in nullplatform, so you can restore it whenever you need it.

Use archive when you're decommissioning gradually, pausing a service you may need again, or cleaning up lists without losing configuration. Hard delete is still available, with its usual guards, for when you're sure you won't need the service again.

How archiving works​

When you archive a service or link:

  • The instance moves to the archived status, and archived_at records when it happened.
  • If the specification has an archive action, nullplatform runs it so your infrastructure can react (for example, quarantining a queue or pausing a database).
  • For links, nullplatform removes the link's parameters from the application. Restoring the link recreates them.
  • The instance and its attributes stay stored and restorable at any time.

Restoring works the same way in reverse: the instance moves to updating and then back to active, running the unarchive action if the specification has one.

Rules and guards​

RuleDetail
Archivable statusesYou can archive from active, failed, or cancelled.
Services with linksA service can only be archived when all of its links are already archived.
Restoring linksA link can only be restored while its parent service is active.
DeletingDelete works on archived instances too. Deleting a service still requires removing its links first, including archived ones.
DuplicatesYou can't create a service or link that matches an archived one (same specification, entity, and dimensions). The error names the archived instance, so you can restore it or delete it first.
info

Archiving requires the ordinary write permission on the service, not the delete permission. Archive is recoverable, so it doesn't need the stricter permission that hard deletes require.

Archive and restore​

Archiving is a status change: set the instance's status to archived, and back to active to restore it. You can do it from the UI, from the CLI, or with a PATCH request to the service or link API.

  1. Go to Platform settings and open Services → List.
  2. Find the service you want to archive and open its actions menu. Archive is only offered for services in active, failed, or cancelled status.
  3. Confirm in the dialog. It asks you to type archive, and reminds you that all of the service's links must be archived or deleted first.
The services list with a row's actions menu open, showing Archive between Set desired version and the destructive Mark as failed and Delete options, and the Show archived toggle above the table

To restore a service, first bring the archived ones into view: turn on the Show archived toggle, or pick Archived in the status filter. The same actions menu then offers Restore, also behind a confirmation.

Links work the same way from the service's links list: Archive removes the link's parameters from the application, and Restore recreates them. Restore is only available while the parent service is active.

While an instance is archiving, its status chip shows the operation in progress and destructive actions stay disabled until it finishes.

If you manage your services as code, see OpenTofu/Terraform for archiving them from your configuration.

What happens after the request​

Archiving resolves in one of three ways, depending on the specification. This mirrors how delete behaves:

  • The specification has a managed archive action → nullplatform creates and runs the action for you in the same request. The instance answers with status archiving (or updating on restore) and the action appears in actions_in_progress.
  • The specification has an unmanaged archive action → the request returns 400, and you run the archive action yourself, the same way you run any other service action.
  • The specification has no archive action → the status changes directly, with the same guards applied.

An archive request can't include attributes (there is no workflow to apply them to). Other metadata fields in the same patch apply immediately.

note

A restore that resolves as a direct status change enforces the specification's required attributes, like any other direct write to active. If an archived instance has an incomplete attribute set, restore it through the unarchive action, or complete its attributes first.

Filtering archived instances​

The API lists archived instances like any other status, so they show up when you list services or list links until you filter them out. Hiding them is what the UI's Show archived toggle does for you.

To list everything except archived instances, exclude them with status:ne:

curl -L 'https://api.nullplatform.com/service?nrn=<NRN>&status:ne=archived' \
-H 'Authorization: Bearer <token>'

To list only the archived ones, filter by status:

curl -L 'https://api.nullplatform.com/service?nrn=<NRN>&status=archived' \
-H 'Authorization: Bearer <token>'

Both filters work the same way against /link. The status:ne filter combines with status as an AND, so ?status=archived&status:ne=archived returns nothing. Fetching an instance by ID works regardless of its status.

Archiving also changes what the has_links filter returns. It counts only links that are neither archived nor deleted, so a service whose links are all archived comes back under ?has_links=false. A link that is still archiving counts as a link, because the operation hasn't landed yet.

Enable archive on your specifications​

Whether archive runs a workflow depends on the service specification:

  • New specifications created with use_default_actions get the archive action generated automatically, alongside create, update, and delete. The unarchive action is never auto-generated.
  • Existing specifications are never modified automatically. You opt in explicitly by creating the action specification, from the CLI or the API.
np service specification action specification create \
--serviceSpecificationId <SPEC_ID> \
--body '{
"name": "Archive service",
"type": "archive"
}'

Create a second one with "type": "unarchive" to run a workflow on restore too. Link specifications work the same way, through their own action specifications.

For specifications using default actions, nullplatform generates the action's parameters and results schemas from the specification's attributes and keeps them in sync on every specification update. Sending your own parameters or results returns a 400.

Once you've opted in, nullplatform owns the action's content: PATCH is refused, and DELETE is how you opt out. For agent-backed specifications (use_default_actions: false), you author both action types with your own schemas, like any other action.

tip

Opt in to both archive and unarchive together. If only archive exists, archiving runs your workflow but restoring falls back to a direct status change, so nothing ever tells your infrastructure to undo the archive.

OpenTofu/Terraform​

If you manage your specifications as code with the nullplatform IaC provider, the opt-in is a nullplatform_action_specification resource carrying only the name, the type, and the parent specification reference. Leave parameters and results out: nullplatform generates them, and sending your own is refused.

resource "nullplatform_action_specification" "unarchive_queue" {
name = "Restore queue"
type = "unarchive"
service_specification_id = "<SPEC_ID>"
}

Use link_specification_id instead for a link specification.

Which of the two actions you declare depends on where the specification came from:

  • Created with use_default_actions: the archive action already exists, so declaring it fails with There is already an action of type archive. Adopt the generated one with terraform import if you want it in state, and declare only unarchive.
  • Created before archiving existed, or with use_default_actions: false: neither action is generated, so declare both.

You don't need ignore_changes here. The provider treats parameters and results as computed, so the schemas nullplatform generates land in state without showing up as drift. Creating the resource is the opt-in and destroying it is the opt-out, so tofu destroy and terraform destroy behave as expected: archiving falls back to a direct status change.

Archiving the services themselves​

The provider archives service instances too, not just the specification's opt-in. Set archive_on_destroy and terraform destroy archives the service instead of deleting it, leaving the row, its attributes, and its infrastructure in place:

resource "nullplatform_service" "orders_queue" {
name = "orders-queue"
specification_id = "<SPEC_ID>"
entity_nrn = "<APPLICATION_NRN>"
archive_on_destroy = true

timeouts {
delete = "10m"
}
}

To archive or restore on demand instead, set status to archived or active on a service that already exists, and give the resource an update timeout so the apply can wait for the transition. Leave status out of your configuration the rest of the time, so a service archived outside your code isn't restored by the next unrelated apply. The read-only archived_at attribute is available as an output.

warning

archive_on_destroy is read from state, so the apply that sets it has to run before the destroy that relies on it. Adding the flag and destroying in the same run still hard-deletes the service.

The nullplatform_service resource documents the full destroy behavior, including how force_destroy and import interact with archive_on_destroy.

Implement archive in your service workflows​

For agent-backed services, archive and unarchive actions run through the same workflow and in the same working directory as your create and update actions. Archive is one more state your module applies, not a separate code path: the same apply runs, and your code decides what "archived" means for the underlying resource.

A typical pattern:

  1. Derive an archived flag in your module from the action being executed, falling back to the service's status so that a later update doesn't accidentally un-archive the resource.
  2. Use that flag to apply the archived state conditionally. For example, an SQS queue module can attach a queue policy that denies sending and receiving messages while archived. The queue keeps its name, ARN, and messages; restoring removes the policy.
  3. Remember that archive and unarchive actions don't carry creation parameters. If your module reads inputs from action parameters, resolve them from stored state or outputs when parameters are empty.
warning

Make sure every execution path of your service treats archive and unarchive as an apply. If your automation only maps known action types and defaults everything else to a plan or a no-op, an archive action will report success without touching your infrastructure.

Deploy your workflow changes before you create the archive and unarchive action specifications. If the actions exist first, archiving runs an apply with no changes: the service ends up marked as archived while your infrastructure stays untouched.