InterLAB tools · 5 domains · 5 dimensions · ADR

Tech Stack Advisor

Pick a layer — UI, backend, mobile app or database — and answer questions about the product, the team and the constraints. The tool shows two or three suitable options, a comparison by product fit, team experience, maintenance, performance and security, the conditions that would change the answer — and builds an architecture decision record (ADR).

Free, no sign-up

Step 1 of 5Domain

What are you choosing?

Start with the layer. Only technologies of the same layer are compared: a UI framework never competes with a database.

Decision domain

Versions of answers and ADR

Versions

No versions yet. Save one before big changes — you can return to it and compare.

Answers, the ADR and versions are stored only in this browser.

How the tool works

  1. First, the decision domain

    Web frontend, backend and API, cross-platform mobile, native mobile, or the primary database. Only technologies of the same layer are compared: Next.js never competes with Flutter, nor React with PostgreSQL.

  2. Then, hard constraints

    Requirements an option cannot meet exclude it before the comparison. The reason is shown in the result.

  3. Then, trade-offs

    Each remaining option is rated per criterion: 0 — a limitation, 1 — with caveats, 2 — a strength. The 0–3 criterion weight comes from your answers; the total measures fit with your answers, not “technology quality”.

  4. The result

    Two or three options from one layer with reasons, a summary across five dimensions (product requirements, team experience, maintenance cost, performance, security), a comparison table, the conditions that change the recommendation (which single answer moves another option to first place), uncertainty, and InterLAB library materials.

  5. Architecture decision record (ADR)

    Title, status “Proposed” or “Accepted” (with the decider for “Accepted”), date, context and key answers, decision drivers with weights, options considered and excluded, the chosen option (with a justification if it is not the top one by total), consequences, conditions to revisit and uncertainty. Markdown, PDF via print, and JSON together with the answers.

Hard constraints

  • UI is a portal with roles and complex state → a static site is excluded.
  • Backend: Python code must run in the API process → Node.js and Spring Boot are excluded.
  • Mobile app: needs APIs browsers do not offer (widgets, system integrations) → the PWA is excluded.
  • Native development for a single platform → Kotlin Multiplatform and Compose Multiplatform are excluded: shared code needs two platforms.
  • Database: several app servers write to it over a network → SQLite is excluded (the SQLite docs recommend a client/server DBMS for that).
  • The existing stack must be kept → all other options in the layer are excluded.

If the constraints exclude every option, the tool does not pick the “least bad” one; it reports the conflict and shows which single answer change resolves it.

Criteria, ratings and weights

The tables below are generated from the same code as the calculation — rules v1.1 (2026-10-13). Each criterion belongs to one of five dimensions. Ratings were checked against the official documentation of each technology; where there is no sound basis to tell options apart, they are rated equally (for example, performance and secret storage in the native domain). The tool does not assert specific versions or library compatibility.

Product requirements

Web frontend
Ready HTML for search and previews; Complex UI: state, forms, roles
Backend and API
One language and shared types with clients; Admin and reference-data editors; Next to Python code (data, ML); Quick start for a small API
Mobile app: one codebase for both platforms
Publishing to the App Store and Google Play; Access to device APIs; Offline operation; Web version from the same code; System UI controls; Identical branded UI
Mobile app: native development
New and deep OS APIs; Platform-native UI; Identical branded UI
Primary database
Relations, reports, JOINs, transactions; Flexible record structure

Team experience

Web frontend
Team experience
Backend and API
Team experience
Mobile app: one codebase for both platforms
Team experience
Mobile app: native development
Team experience
Primary database
Team experience

Maintenance cost

Web frontend
Hosting simplicity; Built-in conventions: routes, data, rendering
Backend and API
Structure for a long-lived system; Built-in production tooling; Version support windows
Mobile app: one codebase for both platforms
Shipping updates; Mandatory updates for store requirements
Mobile app: native development
Code shared between Android and iOS; Long-term support: codebases and dependencies
Primary database
No separate database server; Major version upgrades

Performance

Web frontend
First load on low-end devices
Backend and API
Heavy computation inside the API process
Mobile app: one codebase for both platforms
Dense animation and long lists
Mobile app: native development
Performance
Primary database
Spreading writes across servers

Security

Web frontend
Attack surface and security updates
Backend and API
Built-in protections
Mobile app: one codebase for both platforms
Storing secrets on the device
Mobile app: native development
Storing secrets on the device
Primary database
Access control inside the database
Comparison dimensions by domain

Team experience (team experience)

Static site
by experience
React + Next.js
by experience
React SPA
by experience
Vue + Nuxt
by experience
Weight from answers
3: Tight timing: a familiar stack speeds up the first release; 2: Normal timing; 1: There is time to learn

Ready HTML for search and previews (product requirements)

Static site
2 — Pages are ready-made HTML files
React + Next.js
2 — SSR and SSG serve ready HTML
React SPA
0 — Content appears only after JavaScript runs in the browser
Vue + Nuxt
2 — SSR and SSG serve ready HTML
Weight from answers
3: Search is the main channel; 1: Search matters for some pages; 0: Search does not matter

Complex UI: state, forms, roles (product requirements)

Static site
0 — No app framework: state and logic would be hand-built
React + Next.js
2 — React components, routes and server code in one project
React SPA
2 — React components; routing and data via separate libraries
Vue + Nuxt
2 — Vue components, routes and server code in one project
Weight from answers
3: The UI is complex; 2: The UI is moderately complex; 0: The UI is simple

Hosting simplicity (maintenance cost)

Static site
2 — Any static host or CDN
React + Next.js
1 — Server Actions, cookies and ISR need a Node.js server; static export disables them
React SPA
2 — The build is static files
Vue + Nuxt
1 — SSR needs a Node.js server; static generation is possible
Weight from answers
3: Only static hosting is available; 1: No special hosting limits

Built-in conventions: routes, data, rendering (maintenance cost)

Static site
1 — A generator’s conventions are enough for a content site
React + Next.js
2 — Folder routes, server and client components
React SPA
0 — You pick routing and data loading yourself; React recommends a framework for new apps
Vue + Nuxt
2 — File-based routing and server rendering
Weight from answers
3: The product will be maintained for years, possibly by another team; 2: Maintenance horizon is unknown; 1: Short horizon

First load on low-end devices (performance)

Static site
2 — Ready HTML and minimal JavaScript
React + Next.js
1 — HTML comes from the server; interactivity follows once JavaScript loads and hydrates
React SPA
0 — Nothing is visible until the JavaScript bundle downloads and runs
Vue + Nuxt
1 — HTML comes from the server; interactivity follows once JavaScript loads and hydrates
Weight from answers
2: Heavy screens and low-end devices: the JavaScript loaded up front matters; 1: Performance requirements are unknown; 0: Normal requirements

Attack surface and security updates (security)

Static site
2 — No server code: protect the hosting and the build
React + Next.js
1 — A server runtime: framework vulnerabilities are fixed by updates that must be applied quickly
React SPA
2 — Static files; authorization lives in the backend
Vue + Nuxt
1 — A server runtime: framework vulnerabilities are fixed by updates that must be applied quickly
Weight from answers
3: Payments, health or regulated data; 2: Personal data; 1: Public data: baseline security hygiene
Web frontend

Team experience (team experience)

Node.js (NestJS or Express), TypeScript
by experience
Spring Boot
by experience
Python + FastAPI
by experience
Python + Django
by experience
Weight from answers
3: Tight timing: a familiar stack speeds up the first release; 2: Normal timing; 1: There is time to learn

One language and shared types with clients (product requirements)

Node.js (NestJS or Express), TypeScript
2 — TypeScript on the server and clients
Spring Boot
0 — Different language: types come from a contract (e.g. OpenAPI)
Python + FastAPI
0 — Different language: types via the OpenAPI schema
Python + Django
0 — Different language: types come from a contract
Weight from answers
2: Clients use TypeScript; shared types matter; 0: Shared types do not matter; 0: Only services call the API

Structure for a long-lived system (maintenance cost)

Node.js (NestJS or Express), TypeScript
1 — NestJS provides an architecture (modules, DI); with Express the team owns the structure
Spring Boot
2 — Layers, starters, auto-configuration
Python + FastAPI
1 — Routes, validation and Depends; the rest you assemble
Python + Django
2 — ORM, migrations, auth and conventions included
Weight from answers
3: The product will be maintained for years, possibly by another team; 2: Maintenance horizon is unknown; 1: Short horizon

Admin and reference-data editors (product requirements)

Node.js (NestJS or Express), TypeScript
1 — Added via libraries or built by hand
Spring Boot
1 — Added via libraries or built by hand
Python + FastAPI
1 — Added via libraries or built by hand
Python + Django
2 — An automatic model-based admin — for internal users
Weight from answers
2: Staff need an admin; 0: No admin needed

Next to Python code (data, ML) (product requirements)

Node.js (NestJS or Express), TypeScript
0 — Python code runs as a separate service
Spring Boot
0 — Python code runs as a separate service
Python + FastAPI
2 — Same language and process
Python + Django
2 — Same language and process
Weight from answers
2: Python in-process is preferred; 0: No effect, or handled as a hard constraint

Quick start for a small API (product requirements)

Node.js (NestJS or Express), TypeScript
2 — Express is minimal; NestJS has more concepts
Spring Boot
1 — For a small service there are more concepts and configuration up front
Python + FastAPI
2 — A route, a Pydantic model — and API docs are ready
Python + Django
1 — Many conventions from day one
Weight from answers
2: A fast first release matters; 1: Normal timing; 0: Timing is not pressing

Built-in production tooling (maintenance cost)

Node.js (NestJS or Express), TypeScript
1 — Metrics and health checks via libraries
Spring Boot
2 — Actuator: health, metrics, auditing over HTTP or JMX
Python + FastAPI
1 — Metrics and health checks via libraries
Python + Django
1 — Metrics and health checks via libraries
Weight from answers
2: Long-term operation; 2: Other services rely on the API — observability and health checks matter; 1: Normal operation

Heavy computation inside the API process (performance)

Node.js (NestJS or Express), TypeScript
0 — Node.js guide: move heavy computation off the Event Loop; if there is a lot of it, reconsider whether Node.js fits
Spring Boot
2 — JVM multithreading
Python + FastAPI
1 — CPython’s GIL: one thread runs Python bytecode; use processes or libraries that release the GIL
Python + Django
1 — CPython’s GIL: one thread runs Python bytecode; use processes or libraries that release the GIL
Weight from answers
3: Heavy computation in requests; 0: Normal load

Version support windows (maintenance cost)

Node.js (NestJS or Express), TypeScript
1 — A Node.js LTS line lasts about 30 months; NestJS and Express have their own release cycles — track both
Spring Boot
1 — Free support for a Spring Boot minor version lasts about 13 months: upgrade regularly
Python + FastAPI
1 — 0.x versions: the FastAPI docs warn of breaking changes in minor releases — pin versions
Python + Django
2 — LTS releases get security fixes for at least three years
Weight from answers
2: The product will be maintained for years, possibly by another team; 1: Maintenance horizon is unknown; 0: Short horizon

Built-in protections (security)

Node.js (NestJS or Express), TypeScript
1 — In Express, protections come from third-party packages (Helmet, brute-force protection for sign-in); NestJS has security headers and rate limiting in official modules, the rest via packages
Spring Boot
2 — Spring Security: authentication, authorization, CSRF and security headers
Python + FastAPI
1 — OAuth2 and API-key utilities included; other measures are up to you
Python + Django
2 — CSRF, template escaping, SQL-injection protection via the ORM, clickjacking — out of the box
Weight from answers
3: Payments, health or regulated data; 2: Personal data; 1: Public data: baseline security hygiene
Backend and API

Team experience (team experience)

PWA
by experience
React Native + Expo
by experience
Flutter
by experience
Weight from answers
3: Tight timing: a familiar stack speeds up the first release; 2: Normal timing; 1: There is time to learn

Publishing to the App Store and Google Play (product requirements)

PWA
1 — Through packaging (e.g. PWABuilder); each store has its own rules
React Native + Expo
2 — A regular store build
Flutter
2 — A regular store build
Weight from answers
3: Stores are mandatory; 1: Store need is undecided; 0: Stores are not needed

Access to device APIs (product requirements)

PWA
1 — Within browser APIs; support varies by platform
React Native + Expo
2 — Expo and community modules, or your own native module
Flutter
2 — Plugins, or your own code via platform channels
Weight from answers
3: APIs beyond the browser are needed; 2: Standard device APIs are needed; 0: Device APIs are hardly needed

Offline operation (product requirements)

PWA
1 — Service Worker and cache; Background Sync is not available in all browsers
React Native + Expo
2 — A local on-device database and your own sync
Flutter
2 — A local on-device database and your own sync
Weight from answers
3: Offline-first; 1: Loaded content must be shown offline; 0: Offline is not needed

Web version from the same code (product requirements)

PWA
2 — It is the web
React Native + Expo
1 — React Native for Web in Expo
Flutter
1 — Flutter web
Weight from answers
2: Web from the same code is needed; 0: No web needed

System UI controls (product requirements)

PWA
1 — A web interface
React Native + Expo
2 — Components become native Android and iOS views
Flutter
1 — Its own widgets that mimic system ones
Weight from answers
2: Strictly platform-native UI; 0: Not required

Identical branded UI (product requirements)

PWA
1 — Web layout, depends on the browser
React Native + Expo
1 — Possible, but controls stay system ones
Flutter
2 — Draws the UI itself: looks the same on all OS versions
Weight from answers
3: An identical branded UI is needed, and it is complex; 2: An identical branded UI is needed; 0: Not required

Shipping updates (maintenance cost)

PWA
2 — Update on the server, no store review
React Native + Expo
1 — New versions go through the stores
Flutter
1 — New versions go through the stores
Weight from answers
2: Release speed matters; 1: A normal release cycle

Mandatory updates for store requirements (maintenance cost)

PWA
2 — Without store builds, target SDK requirements do not apply (they do once packaged for a store)
React Native + Expo
1 — Stores regularly raise target SDK requirements: upgrade React Native and Expo and rebuild
Flutter
1 — Stores regularly raise target SDK requirements: upgrade Flutter and rebuild
Weight from answers
2: The product will be maintained for years, possibly by another team; 1: Maintenance horizon is unknown; 0: Short horizon

Dense animation and long lists (performance)

PWA
1 — Within the browser engine: smoothness depends on the browser and the device
React Native + Expo
2 — Native views; lists and animations via dedicated components
Flutter
2 — Code is compiled ahead of time; its own engine draws the UI
Weight from answers
2: Dense animation, long lists, low-end devices; 1: Performance requirements are unknown; 0: Normal requirements

Storing secrets on the device (security)

PWA
1 — Browser storage only; the system Keychain and Keystore are out of reach
React Native + Expo
2 — Keychain and Keystore via expo-secure-store
Flutter
2 — Keychain and Keystore via plugins
Weight from answers
3: Payments, health or regulated data; 2: Personal data; 1: Public data: baseline security hygiene
Mobile app: one codebase for both platforms

Team experience (team experience)

Two native apps
by experience
Kotlin Multiplatform
by experience
Compose Multiplatform
by experience
Weight from answers
3: Tight timing: a familiar stack speeds up the first release; 2: Normal timing; 1: There is time to learn

New and deep OS APIs (product requirements)

Two native apps
2 — Right after the platform SDK ships
Kotlin Multiplatform
2 — UI and platform code are native
Compose Multiplatform
1 — Native views are embedded through interop
Weight from answers
3: Deep APIs and new OS features are needed; 1: Standard APIs; 0: No special APIs

Platform-native UI (product requirements)

Two native apps
2 — Compose and SwiftUI are the system frameworks
Kotlin Multiplatform
2 — The UI is native on each platform
Compose Multiplatform
1 — A shared Compose UI; SwiftUI and UIKit via interop
Weight from answers
2: Strictly platform-native UI; 0: Not required

Code shared between Android and iOS (maintenance cost)

Two native apps
0 — Every feature is built twice
Kotlin Multiplatform
1 — Shared business logic
Compose Multiplatform
2 — Shared logic and UI
Weight from answers
3: Tight timing: duplication is costly; 2: Normal timing; 1: There is slack

Identical branded UI (product requirements)

Two native apps
1 — Two UIs must be kept identical by hand
Kotlin Multiplatform
1 — Two UIs must be kept identical by hand
Compose Multiplatform
2 — One UI for both platforms
Weight from answers
2: An identical branded UI is needed; 0: Not required

Long-term support: codebases and dependencies (maintenance cost)

Two native apps
1 — Two codebases, but only Apple and Google tooling
Kotlin Multiplatform
1 — Shared logic in one codebase; adds a dependency on Kotlin Multiplatform tooling
Compose Multiplatform
1 — One codebase; the iOS UI depends on Compose Multiplatform
Weight from answers
2: The product will be maintained for years, possibly by another team; 1: Maintenance horizon is unknown; 0: Short horizon

Performance (performance)

Two native apps
2 — Native code; no difference is claimed without measuring your own scenario
Kotlin Multiplatform
2 — Native code; no difference is claimed without measuring your own scenario
Compose Multiplatform
2 — Native code; no difference is claimed without measuring your own scenario
Weight from answers
2: Dense animation, long lists, low-end devices; 1: Performance requirements are unknown; 0: Normal requirements

Storing secrets on the device (security)

Two native apps
2 — Direct access to Keychain and Keystore
Kotlin Multiplatform
2 — Keychain and Keystore via platform code
Compose Multiplatform
2 — Keychain and Keystore via platform code
Weight from answers
3: Payments, health or regulated data; 2: Personal data; 1: Public data: baseline security hygiene
Mobile app: native development

Team experience (team experience)

PostgreSQL
by experience
MySQL
by experience
MongoDB
by experience
SQLite
by experience
Weight from answers
3: Tight timing: a familiar stack speeds up the first release; 2: Normal timing; 1: There is time to learn

Relations, reports, JOINs, transactions (product requirements)

PostgreSQL
2 — Relational model, transactional migrations
MySQL
2 — Relational model
MongoDB
1 — Relations via embedding or $lookup; multi-document transactions exist, but the model is document-centred
SQLite
2 — Relational model
Weight from answers
3: Many relations and reports; 2: Mostly relational; 0: Few relations

Flexible record structure (product requirements)

PostgreSQL
2 — jsonb with GIN indexes
MySQL
1 — A JSON type; indexes via generated columns
MongoDB
2 — The document model
SQLite
1 — JSON functions
Weight from answers
3: Data is self-contained documents; 2: Some fields are flexible; 0: The structure is strict

Spreading writes across servers (performance)

PostgreSQL
1 — Partitioning is built in; spreading across servers needs external tools
MySQL
1 — Clustering is a separate architecture
MongoDB
2 — Built-in sharding
SQLite
0 — One file, one writer
Weight from answers
3: Write traffic beyond one server is expected; 1: Volume is unknown; 0: One server is enough

No separate database server (maintenance cost)

PostgreSQL
1 — A separate server or a managed service
MySQL
1 — A separate server or a managed service; often provided by hosting
MongoDB
1 — A separate server or a managed service
SQLite
2 — A file next to the app
Weight from answers
2: Tight timing and a single app server; 0: No effect

Major version upgrades (maintenance cost)

PostgreSQL
1 — A major upgrade means pg_upgrade or dump and restore; plan it ahead
MySQL
1 — Major upgrades are planned ahead along the documented upgrade paths
MongoDB
1 — Major versions are upgraded one at a time, in sequence
SQLite
2 — The file format is stable and backward compatible; the project commits to support through 2050
Weight from answers
2: The product will be maintained for years, possibly by another team; 1: Maintenance horizon is unknown; 0: Short horizon

Access control inside the database (security)

PostgreSQL
2 — Roles, privileges and row-level security policies
MySQL
2 — Users and privileges down to columns
MongoDB
2 — Role-based access control (RBAC)
SQLite
1 — No users or privileges: access depends on file permissions and application code
Weight from answers
3: Payments, health or regulated data; 2: Personal data; 1: Public data: baseline security hygiene
Primary database

Limitations

  • Framework speed is not ranked by benchmarks: the performance criteria describe mechanisms (JavaScript loaded up front, heavy computation in the API process, spreading writes), and demanding targets are checked with a prototype and a load test.
  • The security criteria compare built-in mechanisms and attack surface, not the security of your product: that depends on code, configuration and updates.
  • Hiring in your region is not assessed — check job posts and CVs for each option.
  • Options within a domain are limited to the most common ones; if your candidate is not listed, the criteria still work as a checklist.
  • The ADR records your choice and its grounds but does not replace an engineering review: you state the status and the decider; it is not an electronic signature.

Privacy

  • The comparison runs in your browser: the tool itself does not send your answers to a server, and they never appear in the page address.
  • Answers, the ADR and versions are stored only in this browser (localStorage); “Clear all” deletes them. Export files are created on your device.
  • Analytics receives only the fact of a comparison with its domain and the fact of an ADR export with its format and status — not the answers or the decision text.
  • The result reaches us only if you send a request yourself and keep the “Attach the result” box ticked — the form shows exactly what will be sent.

Related tools

All tools · 40
Tell us about your task — we'll review your request and get back to you

Want the choice reviewed for your project?

A technical consultation is a paid engineering review of options and risks. The first short conversation about the format is free; the cost is set after a brief and an agreed scope.

  • The first short conversation is free — we choose the format
  • NDA — yours or ours
  • Pricing after a brief and an agreed scope

Please do not send passwords, access keys or source code through this form — we will agree a safe way to share access separately.

By clicking the button you agree to the processing of your personal data.