
On this page
Authentication is infrastructure. Treat it like anything you'd manage with Terraform. Version-control it in a GitOps pipeline. Hand it to on-call with a runbook. Choose the wrong tool and you're not just carrying tech debt — you're carrying it at 2 am.
We chose AWS Cognito because it was already in the AWS ecosystem. The free tier covers 50,000 MAU. That math looked good in a spreadsheet. Three weeks later: a password reset flow redirected to the wrong URI. Twelve documentation tabs open. Nobody could explain why.
This is a detailed account of what broke. Where the architecture created operational problems. What we'd pick if we were starting today. No fabricated metrics. No invented quotes. Just the actual pain points and a decision framework for teams evaluating aws cognito startup architecture now.
The Documentation Problem Is Structural, Not Incidental
Cognito's docs are not bad because AWS writes bad documentation. Cognito tries to serve five audiences at once. Enterprise architects. Frontend engineers. Mobile developers. CLI users. Amplify users. No clear separation exists between those contexts.
You search for "Cognito custom attribute validation." You land three pages deep into a document about directory schemas. The page assumes you've already absorbed four prerequisites you didn't know existed.
The code samples compound this. Some reference the Amplify v1 API. Others use raw aws-sdk. Others use Amplify v6, which is architecturally incompatible with v5 in ways the migration guide undersells. There's no single canonical path through the implementation. That's a legitimate problem when you're trying to ship fast and keep your infrastructure as code auditable and clean.
A practical signal: if you're evaluating Cognito and your proof-of-concept tab count exceeds fifteen, that's not user error. That's a documentation architecture problem you'll carry into production.
Amplify v6 Was a Breaking Change, Not an Upgrade
This one deserves its own section because it cost real engineering hours.
Amplify v5 → v6 is not a version bump with changed signatures. It's a rewrite of the API surface. Auth flows built against v5 — Auth.signIn(), Auth.currentSession() — do not exist in v6. The v6 equivalents are signIn(), fetchAuthSession(), imported from @aws-amplify/auth instead of the top-level package.
Upgrade from v5 without reading the migration guide carefully. Your auth flows break silently. Not every failure throws a clear error. Some just return unexpected shapes.
In a GitOps workflow, this creates an operational smell. Library behaviour diverges from Helm values in ways a PR review never surfaces. Your SRE team cannot diff a semantic API change the way they diff a Helm override.
Pin Amplify versions in package.json. Treat any major version upgrade as a migration project — its own ticket, its own staged rollout. Not a Friday afternoon dependency bump.
Local Development Is Not a Solved Problem
Cognito is cloud-first. There is no official local emulator. You're always hitting real AWS endpoints during development unless you build around community tooling.
Your main options:
Option 1: cognito-local (community, unmaintained as of late 2025)
Option 2: LocalStack (Pro tier required for full Cognito support)
Option 3: Mock the Cognito client in your test layer entirely
Option 4: Use a dedicated dev user pool per engineerOption 4 is operationally honest. It costs more and adds pool-management overhead. Option 3 works if your team enforces strict test hygiene. Accept that you're testing your mock — not Cognito's token behaviour.
For on-call purposes, this matters. If staging is where edge cases first surface, you are creating on-call noise. Prefer Option 4. Use infrastructure as code to manage pool lifecycle via Terraform. Destroy and recreate pools per feature branch if your cadence supports it.
What Most AWS Cognito Startup Teams Get Wrong
The most expensive mistake is treating the Cognito User Pool as mutable state you can fix later. You can't.
Once created as custom, an attribute stays custom forever. If email should have been standard and you created custom:email, there is no alter-table equivalent. Your options are:
- Migrate users to a new pool with a scripted process and forced password reset
- Build workarounds in your application layer that translate between the wrong schema and the right one
In production, option 1 means a user-facing migration event. Option 2 means carrying complexity your SRE team hits during incidents with no runbook.
The correct approach is to treat the User Pool configuration as immutable infrastructure. Define it fully in Terraform before you create it:
resource "aws_cognito_user_pool" "main" {
name = "startup-users-${var.environment}"
username_attributes = ["email"]
auto_verified_attributes = ["email"]
schema {
name = "email"
attribute_data_type = "String"
required = true
mutable = true
string_attribute_constraints {
min_length = 5
max_length = 254
}
}
password_policy {
minimum_length = 12
require_uppercase = true
require_lowercase = true
require_numbers = true
require_symbols = false
}
}Review it with the rigour of a database schema migration. Get sign-off before terraform apply. Once users are in the pool, the schema is permanent.
When Cognito Is Actually the Right Call
This isn't a "Cognito is always wrong" post. There are contexts where it's the correct choice:
- Your team already operates heavily in AWS and your IAM posture benefits from Cognito-to-AWS integration
- You need SAML 2.0 or OIDC federation with an enterprise IdP and prefer not to manage the plumbing
- Your compliance requirements mandate data residency in a specific AWS region
- You're building a B2B product where your customers' IT teams will configure the identity federation themselves
Outside these cases, Cognito's hosted-UI limits, local dev friction, and immutable schema are operational costs that compound.
Alternatives Worth Evaluating
| Provider | Self-hosted | Free Tier | Local Dev | Helm Chart Available |
|---|---|---|---|---|
| Clerk | No | Yes (10k MAU) | Yes (dev mode) | N/A |
| Auth0 | No | Yes (7,500 MAU) | Yes (dev tenant) | N/A |
| Keycloak | Yes | N/A | Yes (Docker) | Yes |
| Supabase Auth | Optional | Yes (50k MAU) | Yes (Docker) | Community |
| Ory Kratos | Yes | N/A | Yes (Docker) | Yes |
Running Kubernetes on AKS with a GitOps delivery model? Keycloak via Helm is worth the overhead if you have a dedicated DevOps function. You get full schema control, local dev with Docker Compose, and a Helm chart versioned in your GitOps repo.
Without that function, Clerk or Auth0 dev experience is substantially better than Cognito's. Their pricing at early MAU levels is comparable to the engineering hours you'd spend fighting Cognito.
FAQ
Can you export users out of a Cognito User Pool if you need to migrate?
Export usernames, email addresses, and custom attributes via the ListUsers API. You cannot export password hashes — Cognito doesn't expose them. Migration to a new pool or provider requires a forced password reset for all users. Plan for this before committing to Cognito.
Is there a way to run Cognito locally without LocalStack Pro?
The community project cognito-local (npm: @aws-amplify/backend) provides a lightweight local emulator for the most common Cognito flows. As of mid-2026, it is partially maintained. It covers sign-up, sign-in, and token generation well enough for unit tests. It diverges on custom attribute validation and trigger lambdas. For Lambda triggers: test against a real dev user pool.
Does managing Cognito with Terraform actually solve the schema problem?
Partially. Terraform can prevent you from accidentally applying attribute changes that Cognito will reject. Terraform cannot change an attribute already created as custom. It errors on plan if you modify the attribute_data_type or name of an existing schema block. What Terraform gives you is reviewability. Schema configuration is versioned, peer-reviewed, and auditable. That catches mistakes before apply.
What's the on-call story with Cognito?
Cognito failures surface as HTTP 400s. Error codes like UserNotFoundException and NotAuthorizedException are specific enough to be actionable. Generic enough to require context. Your runbook should map the most common Cognito error codes to mitigation steps. SRE teams without that runbook will read Cognito docs under pressure. That is not a fast process.
If we're already using Cognito in production, should we migrate away?
Probably not immediately. The migration cost is high. Forced password reset. New pool provisioning. Application code changes. Updated infrastructure as code. The case strengthens when adding auth features — social login, MFA, custom flows — and Cognito slows you down. Stable auth layer, friction as the main cost? Incremental hardening beats a live migration.
Talk to Devolity Before You Commit to the Architecture
Auth infrastructure decisions compound quickly. The schema you choose today follows you to your SOC 2 audit and your first major incident.
Devolity Business Solutions works with engineering teams on cloud architecture reviews, DevOps pipeline design, and infrastructure as code foundations. Evaluating auth providers? Designing a Kubernetes deployment on AKS or EKS? Want a second opinion before a major infrastructure commitment? Schedule a technical consultation with our team.
This post was informed by a post-mortem published by Josh Karamuth at joshkaramuth.com. The operational analysis and recommendations are Devolity's own.
We don't do generic advice. We review your actual architecture, deployment model, and team capacity — then give you a direct recommendation.
##-----------
OVERVIEW The agent we’ll build has six components, covered in this order:
Sources - A named list of places to read Destination - One place the agent may write Agent - The model, tools, and run steps in agent.md Schedule - A cron schedule Memory - Your preferences and the agent's own memory Guardrails - Read-only access wherever the agent only reads, and a spending cap per run Architecture of the agent: a schedule wakes the agent, which reads from its sources and posts a brief to one destination for the reader. Memory holds the agent's state and the reader's preferences, and guardrails surround the agent.

Give the agent its own, scoped credentials
Next Steps & Enterprise Guidance
Implementing production-grade cloud, security, and DevOps architectures requires continuous governance and hands-on operational rigor.
Whether you are reviewing compliance roadmaps or planning zero-downtime infrastructure cutovers, Devolity's engineering practice partners with your team from assessment through 24/7 delivery. Contact our team today to schedule a technical discovery session.
Enjoyed this article? Get our DevOps & Cloud newsletter
Production blueprints, zero-downtime cutover notes, and security practices twice a month. Zero spam.
Twice a month · No spam · Unsubscribe anytime
More posts like this

Hosting
What managed hosting covers after the server is online
May 21, 2026 · 2 min readHosting

Artificial Intelligence
Instagram AI Filter Scandal: How Fake Beauty is Destroying Gen Z
May 13, 2026 · 26 min readArtificial Intelligence

Artificial Intelligence
AI Health Coach: Lost 15 Kg Without a Gym — Here's How
Apr 11, 2026 · 27 min readArtificial Intelligence