Kizaki
ReferenceInspire

Files And Network

Model file fields in Inspire and declare outbound network policy for your application runtime.

Two features that define the application boundary: file determines how uploaded bytes become part of your data model; network determines which external systems your server-side code can reach.

This page also covers the raw integration path: routes(...) for inbound webhooks, req.rawBody for signature verification, network {} for outbound allowlists, and @secret(...) for provider keys. Use integrations {} when you need managed per-user delegated OAuth.

File Fields

The Core Model

A file is a field on an entity, not a bucket path.

entity Attachment {
  name: string,
  file: file,
  ownerId: __User.id,

  @grant read, write, delete where resource.ownerId == principal.id
}

Authorization, lifecycle, namespace scoping, and cleanup all derive from the owning entity. The object store is an implementation detail.

Declaration Patterns

Use a file field when one entity owns one uploaded file.

entity UserProfile {
  displayName: string,
  avatar: file?,
  userId: __User.id,

  @grant read to *
  @grant write where resource.userId == principal.id
}

One File Per Field

A single file field holds one file. Arrays of file are not supported; the compiler rejects them. Use a separate entity for collections:

entity TaskAttachment {
  taskId: Task.id @onDelete(cascade),
  file: file,
  uploadedBy: __User.id,
  label: string?,

  @grant read to * via TeamMembership
    where TeamMembership.teamId == resource.task.teamId

  @grant insert where resource.task.createdBy == principal.id
  @grant delete where resource.uploadedBy == principal.id
}

A collection of files typically needs its own identity, ordering, labels, audit data, and per-file deletion. Model it as an entity.

What The Runtime Stores

File metadata is stored as JSONB on the owning row. Pending uploads are tracked in a system table.

Metadata includes: storage key, file size, MIME type, original filename, and upload timestamp. Application code works with the typed file field, not raw JSONB.

The Upload Lifecycle

A three-step handshake. File bytes do not travel through your application server.

  1. Request upload -- the platform issues a principal-bound upload token and presigned URL. Upload permission is checked before upload begins.
  2. Direct upload -- the client uploads bytes directly to the backing store using the presigned URL.
  3. Confirm upload -- the platform verifies the token, rechecks principal authorization, validates metadata, and writes file JSONB onto the entity row. Until confirmation, the entity has not adopted the file.

Download Flow

  1. The principal reads an entity row they can access
  2. The platform rechecks file-read access when generating the download URL
  3. The client receives a presigned download URL

Authorization

File Authorization Is Entity Authorization

No second authorization system for file storage.

  • Read the entity field → obtain file metadata and download URL
  • Update the entity field → replace the file
  • Delete the entity → associated file follows

All policy patterns apply: ownership, role-based, via junction, public, field-level grants.

Upload And Replace

Uploading or replacing a file follows insert/update authorization on the owning entity. Confirmation re-enters the normal policy path.

Read

Downloading follows read authorization on the entity and field. Composes with field-level grants.

Delete

No independent file-delete permission. Files are deleted when:

  • A nullable file field is cleared
  • A file field is replaced
  • The owning entity is deleted
  • A cascading delete removes the owning row

Lifecycle And Cleanup

Replacement

When a file field is replaced, the runtime writes new metadata and cleans up the old object.

Entity Deletion

Deleting the owning row deletes the associated file object.

Cascade Deletion

File cleanup follows FK cascade deletion.

Orphan Handling

Pending uploads are tracked in __file_pending. Uploads that complete but are never confirmed are treated as controlled in-flight state, not permanent orphans.

Namespaces

File fields on namespaced entities follow the same namespace rules as all other fields. Tenant-scoped entities have tenant-scoped files. Cross-tenant file access requires the same elevated path as cross-tenant data access.

Quotas And Operational Limits

Uploads consume storage, downloads consume bandwidth, and pending uploads need cleanup discipline. Files are part of the application resource model.

Current Runtime Shape

  • JSONB file metadata on the owning row
  • 3-step upload handshake
  • Principal-bound pending uploads in __file_pending
  • Presigned upload and download URLs
  • MIME validation
  • Entity-policy rechecks on confirm and download
  • Mock provider in dev, S3 presigner in configured environments
  • Use file when one row owns one uploaded file
  • Use a separate attachment entity for collections
  • Keep all authorization on the owning entity
  • Treat upload confirmation as the moment the entity adopts the file
  • Let entity deletion and cascade deletion drive file cleanup

Network Policy

network controls which external services server-side code can reach.

network {
  allow: [
    "api.stripe.com",
    "hooks.slack.com",
  ],
  dynamic: false,
}

Use network to keep outbound access explicit at the schema level.

Related guide: File Storage

On this page