Skip to content

Quill

Scheduled Oct 7, 2026

A content model you define, on an API you host.

Replaces

  • Contentful · Contentful GmbH $300 per org per month (Lite), about $3,600/yr at 400 seats
  • Sanity · Sanity AS $15 per seat per month (Growth), about $72,000/yr at 400 seats

Rented, per year

$3,600

Contentful list price at 400 seats.

Owned, per year

$7,680

AWS infrastructure only. Azure is $8,280.

Build

8 weeks

2 engineers. To parity on the ten core features, including the structured editor, the asset pipeline and migration of existing content types, entries, assets and locale values from Contentful or Sanity with the reference graph intact.

Difficulty

3/5

Well-understood shape. Low delivery risk.

Reference organisation: 40 editors, ~120,000 entries across 8 locales, 60 GB of assets, 15M delivery API requests and 2 TB of CDN egress per month, single region origin, prod + non-prod. 3-year Compute Savings Plan on Fargate / 3-year reservation on Container Apps. Aurora minimum 0.5 ACU with non-prod stopped outside business hours. CDN egress modelled at 2 TB/month, which is the largest single line in both figures and scales linearly with traffic. Published-version retention set to 24 months. Excludes vendor support plans. These figures are infrastructure only and exclude the build.

What it is

Quill is a headless CMS: you define content types and fields, editors work in a structured editor with drafts, versions and scheduled publishing, and the content comes out of a read API and a GraphQL endpoint you host behind your own CDN. It suits organisations running more than a handful of sites and locales, where the CMS has become the system of record for marketing, product documentation and legal copy, and where the pricing model has begun to charge for the two things you most want to add — more locales and more people allowed to edit.

Why this one stops making sense

  • Contentful Lite is $300 a month and caps you at 3 locales and 3 roles. The moment you add a fourth language or a fourth editorial role, the only published path is Enterprise pricing on request.
  • Content is a permanent asset with a multi-decade life. Your product pages, your compliance copy and your knowledge base outlive any CMS contract, and getting rich text plus references plus assets out of a proprietary model intact is genuinely hard.
  • Per-seat editing pricing puts a tax on review. The reviewers, translators and legal readers who should be in the workflow are exactly the users you end up leaving out.
  • Delivery-API rate limits and bandwidth allowances turn a traffic spike into a billing event, which is a strange property for the system serving your public website.
  • The content model — your field types, your validation rules, your reference graph — is architecture. It belongs in your repository as migrations, reviewed like schema changes, not clicked into a vendor's web UI.

What ships

  • Content modelling as code: types, fields, validation and references defined in versioned migration files
  • Structured rich text stored as a portable document tree, not HTML, with typed embeds and references
  • Draft, review and published states per entry per locale, with an explicit editorial workflow
  • Full version history with diff and restore on every field
  • Scheduled publishing and unpublishing, including coordinated multi-entry releases
  • Preview: a signed, time-boxed URL that renders the draft state in the real front end
  • Localisation with per-field locale fallback chains and translation status per locale
  • Asset pipeline with on-the-fly resizing, format negotiation to AVIF and WebP, and focal-point cropping
  • REST delivery API plus a generated GraphQL schema, both CDN-cached and versioned
  • Webhooks and a change feed so downstream builds and search indexes update on publish

Data model

SpaceEnvironmentContentTypeFieldEntryEntryVersionLocaleValueLocaleAssetAssetDerivativeReleaseWebhookSubscriptionRoleAuditEvent

Stack

frontend
Next.js 15 App Router + Tailwind for the studio; Slate-based structured editor over a portable text tree
backend
NestJS on Node 22 for the management API; a separate lightweight read service for delivery
database
PostgreSQL 16, entries as JSONB with generated columns for indexed fields, Row Level Security per space
cache
Redis 7 for the delivery service's hot entry cache and for preview token state
queue
BullMQ for asset derivative generation, webhook dispatch and scheduled release execution
auth
OIDC against the customer IdP for the studio; signed delivery tokens scoped per environment for the API
search
PostgreSQL tsvector across entry text per locale, with a per-locale text search configuration
ai
Optional: alt-text generation for assets, translation drafts and tone checks against a house style guide, all through a pluggable LLM gateway with the editor confirming before publish

Parity, honestly

What we match, and what we do not.

The rows marked No are the important ones. If one of them is the reason you bought Contentful, keep buying it — and we will tell you that on the first call rather than the fifth month.

CapabilityContentfulOursNote
Content modelling with references and validationYesYesDefined as migrations in git rather than in a web UI.
Structured rich text with typed embedsYesYes
Draft / published states and version historyYesYes
Scheduled publishing and releasesYesYes
Localisation with fallback chainsYesYesNo locale count limit, which is the specific thing Contentful Lite caps at 3.
Preview of draft content in the real front endYesYes
Image transformation APIYesYesSharp behind the CDN, with the derivative cached forever on an immutable key.
GraphQL delivery APIYesYesGenerated from the same model definition as the REST API.
Unlimited editor and reviewer seatsNoYesSanity is $15 per seat per month; Contentful Lite caps at 20 users. Quill's cost does not move.
Real-time collaborative editing on a single entryYesPartialQuill does presence, field-level locking and live conflict warning. Sanity's character-by-character multiplayer on structured content is genuinely good and we do not match it in the base build; a CRDT editing layer is a separate four-week engagement.
App and extension marketplaceYesNoContentful's App Framework has a real ecosystem — translation vendors, DAM connectors, SEO tools, personalisation — installable in minutes. Quill has a field-plugin API and no marketplace. We integrate the two or three you use; we do not rebuild an ecosystem.
Vendor-operated global delivery network with an uptime SLAYesNoContentful runs a multi-region delivery API with a contractual SLA and a status page you can point at during an incident. Quill runs on your CloudFront or Front Door distribution, which is fast and cheap but the SLA is your cloud provider's and the incident is yours. For a public marketing site that is fine. If your CMS serves a revenue-critical product surface and someone senior wants a vendor to escalate to at 2am, that is a legitimate reason to keep buying.
Content delivery bandwidth included in the pricePartialNoBoth vendors meter bandwidth and so does your CDN. This one is a wash, not a win — we say so rather than counting it as a saving.
Translation management and vendor handoffPartialPartialQuill exports and imports XLIFF per locale and tracks translation status. Connecting to a specific translation vendor is a connector, not a feature.

Reference architecture

Built twice, on purpose.

Every application in Techtons ships with a production architecture for AWS and one for Azure, using the same diagram grammar so you can read them side by side. Your cloud, your account, your bill.

Amazon Web Services

Compute
ECS Fargate (studio-api, delivery, worker) behind an ALB; delivery scaled independently
Data
Aurora Serverless v2 PostgreSQL with a read replica dedicated to the delivery service
Storage and edge
S3 for original assets and generated derivatives, CloudFront in front of both delivery and assets
Identity
Cognito federated to the customer IdP; delivery tokens signed with a KMS asymmetric key
Observability
OpenTelemetry to CloudWatch, plus CloudFront real-time logs sampled for cache-hit ratio
Infrastructure as code
Terraform, with the content model migrations run as a pre-deploy ECS task

Services

ECS FargateALBCloudFrontAurora Serverless v2ElastiCache RedisS3Lambda@EdgeSQSKMSCognitoWAFCloudWatch

The decision worth arguing about

The non-obvious decision is that Quill never issues a CloudFront invalidation, and understanding why explains the whole delivery design. CloudFront gives you 1,000 invalidation paths a month free and charges per path after that, but the real problem is not the price — it is that a publish in a CMS is not one path. Changing a shared component, a navigation entry or a legal footer invalidates thousands of rendered pages, and wildcard invalidations propagate across the edge on their own schedule, which means the editor who just fixed a typo sits watching a stale page and refreshing. So the delivery API is content-addressed instead: every publish creates an immutable content version, and every delivery URL carries that version, which lets us set a one-year max-age and never purge anything. What changes on publish is a single tiny pointer document naming the current version, served with a five-second TTL. A reader therefore pays one extra pointer fetch — usually already in the browser's cache or collapsed into the front end's build — and sees new content within about five seconds worldwide, with zero invalidation cost and no origin stampede, because the pointer is a few hundred bytes and the versioned content behind it was already warm from the preview traffic. The trade-off is real and we name it: storage grows with every published version rather than being overwritten, so a lifecycle policy expires versions older than the retention window, and rollback beyond that window means restoring from the database rather than flipping the pointer. For a content system where the ability to say exactly what was published on a given date is often a legal requirement, keeping the versions is a feature rather than a cost.

Microsoft Azure

Compute
Azure Container Apps (studio-api, delivery, worker), delivery on its own scale rule
Data
Azure Database for PostgreSQL Flexible Server with a read replica for delivery
Storage and edge
Blob Storage for assets and derivatives, Azure Front Door Standard in front of both
Identity
Microsoft Entra ID for the studio; delivery tokens signed with a Key Vault key
Observability
Azure Monitor and Application Insights, with Front Door access logs to Log Analytics
Infrastructure as code
Bicep, migrations run as a Container Apps job before the revision is promoted

Services

Container AppsContainer Apps JobsFront Door StandardPostgreSQL Flexible ServerCache for RedisBlob StorageEntra IDKey VaultEvent GridService BusLog Analytics

The decision worth arguing about

Azure Front Door actually makes the tempting alternative more tempting, which is why the decision is worth restating here rather than copied across. Front Door supports cache purge by path and by wildcard at no per-path charge, so the cost argument against invalidation that applies on CloudFront does not apply on Azure. We still do not use it. Purge on Front Door is asynchronous and propagates across points of presence over a window measured in minutes, and it is rate-limited per profile, so a busy editorial day that publishes forty times an hour can queue purges behind each other. The immutable-version-plus-pointer design gives a consistent five-second worst case regardless of publish rate, and — the reason that matters more than the latency — it behaves identically on both clouds, so the delivery service has one code path rather than a CloudFront branch and a Front Door branch. Where Azure does change the shape is the URL rewriting. We keep the version out of the public URL using the Front Door rules engine to rewrite an incoming clean path into the versioned origin path, reading the current version from the pointer via a rules-engine condition. Front Door Standard caps the number of rules per rule set, and a deployment with many locales and many hostnames will reach that cap, at which point you either simplify the routing or move to Premium. We would rather flag that as a known ceiling than have a customer discover it when they add their ninth market. Asset derivative generation runs as a Container Apps job rather than in an edge function, because Azure has no Lambda@Edge equivalent with the same execution model; the derivative is generated once on first request, written to Blob Storage on an immutable key, and served from cache thereafter.

Sources

Every price on this page, with the page we read it from and the date we read it.

ProductPlanList priceCheckedSource
ContentfulLite$300 / org/month2026-09-05www.contentful.com/pricing/

Contentful lists Lite at $300 per month, including 20 users, 3 roles, 3 locales, 1M API calls and 100 GB of CDN bandwidth. Beyond those limits the only published option is Enterprise, priced on request. The constraint that pushes most organisations off Lite is the locale and role count, not the API calls.

SanityGrowth$15 / seat/month2026-09-05www.sanity.io/pricing

Sanity lists Growth at $15 per seat per month. Enterprise is custom. Usage above the plan's included API requests, bandwidth and asset storage is billed separately on top of the seat price.

Should you still be paying for Contentful?

Two weeks, fixed price. We audit what you actually use, map it against Quill, cost the replacement on your own AWS or Azure account, and give you a delivery plan. If the honest answer is to keep the licence, that is what the report will say.