A backend developer worth hiring designs schemas by asking about access patterns before writing a single table, treats idempotency as a non-negotiable for anything that touches money, and debugs by measuring first rather than guessing. Expect to pay $20–50/hr for experienced offshore developers, $90–160/hr US-based. These signals hold regardless of whether they work in Django, Node.js, Go, or anything else — here is how to evaluate them.
The Framework-Agnostic Skills That Predict Backend Quality
The most common hiring mistake is confusing framework knowledge with backend engineering ability. A developer who has memorised Django's ORM API is not necessarily a good backend developer. A developer who thinks carefully about schema design, failure modes, and observability is — regardless of which framework they reach for.
These are the skills worth testing:
Database Design Under Real Constraints
Good database design is not about normalisation — it is about designing for the queries you will actually run. A developer who designs tables without asking about access patterns first is modelling for theoretical purity, not for your system. That produces schemas that are clean on paper and slow in production.
The specific signals to look for: do they ask about read vs write ratio before deciding on indexing strategy? Do they know when denormalisation is the correct choice? Can they read an EXPLAIN ANALYZE output and identify whether the bottleneck is a missing index, a sequential scan, or a join that's pulling too many rows?
Understanding why indexes matter at the mechanism level separates engineers who use them intuitively from those who add them reactively after production slowdowns. A B-tree index (PostgreSQL's default) stores keys in a sorted, balanced tree structure. Each internal node holds key ranges pointing to child nodes; each leaf node holds a (key, heap pointer) pair pointing to the actual row in the table's heap storage. PostgreSQL stores these nodes in 8KB pages. On a million-row table, the tree is about 4 levels deep, so finding one row costs 4 page reads — O(log n). Without an index, PostgreSQL does a sequential scan, reading all ~10,000 pages in the table — O(n). That difference is invisible on a 1,000-row development database and catastrophic on a 10-million-row production one. These questions have answers that come from experience, not from reading documentation.
API Design With HTTP Semantics
REST is not a style choice — it has rules, and violating them causes downstream problems. PUT is idempotent, POST is not — this matters for retry logic. 422 means the request was well-formed but semantically invalid; 400 means it was malformed — this matters for client error handling. A versioned API is a contract with your clients; breaking it without versioning is a promise broken retroactively.
A backend developer who cannot explain why idempotency matters for payment endpoints has not built a payment flow that survived a network failure. Ask directly: "What happens if a payment webhook is delivered twice?" The answer should describe idempotency key checking before taking any action. Developers who don't know this are a billing incident waiting to happen.
Error Handling and Observability
Production systems fail. The difference between a good and a bad backend developer is whether the system tells you why and where when it does. Structured logging — JSON-formatted log lines with consistent fields for request ID, user ID, endpoint, and duration — is what makes logs searchable. A developer who uses print() for debugging in production code has not had to find a bug in a deployed system under time pressure.
Ask: "How do you handle a background task that fails halfway through processing a payment?" The answer should include retry logic, idempotency checks, and a dead-letter queue or alert for tasks that exhaust retries. A vague answer ("I'd check the logs") is not an answer about handling — it is an answer about discovery after the fact.
Security as a Default, Not an Afterthought
The security fundamentals are not advanced topics — they are baseline. Secrets in environment variables (never hardcoded). SQL injection prevented by ORM discipline or parameterised queries. Rate limiting on authentication endpoints. JWT expiry validated, not just decoded. These are not items to add after launch; they are design choices made on day one.
A developer who is surprised by any of these topics when asked is not ready for production work. A developer who can explain why each one matters — the specific attack it prevents — is treating security as engineering rather than compliance.
Process Discipline (The Signals That Don't Show Up in the Interview)
These framework-agnostic habits reveal whether a developer has worked on codebases maintained by more than one person:
Commit discipline. Small, focused commits with descriptive messages. Developers who commit everything in one giant commit at the end of the day are not thinking about the diff review or the future git bisect. This is visible on GitHub before the interview.
README and documentation quality. Can someone else clone the repository and run it locally without asking questions? A backend developer who does not document the setup process has not worked on a team. Look for: environment variable list, local development instructions, and a note on how to run the tests.
Deployment reproducibility. "It works on my machine" is not a deployment story. A developer who cannot describe how they've deployed their projects — what process manager, what environment variable strategy, what migration approach — has not owned production applications end to end. Connection pooling is a concrete example of production discipline: every new database connection requires a TCP 3-way handshake plus TLS negotiation (~60–120ms overhead) before the first query runs. A backend that opens a new connection per request under 500 concurrent users creates 500 simultaneous TCP handshakes. A connection pool — PgBouncer for PostgreSQL, or a framework-level pool — keeps N connections alive and reuses them, eliminating that overhead entirely. A developer who has not set up a connection pool in production has not operated a backend under load.
Five Interview Questions That Reveal Real Ability
1. "Walk me through how you'd design the data model for a multi-tenant SaaS application."
This reveals whether the developer thinks about the architectural decision before writing code. Good answers describe at least two approaches — shared schema with a tenant_id column, or separate schemas per tenant — and discuss the tradeoffs: shared schema is operationally simpler; separate schemas provide stronger data isolation but increase migration complexity. Weak answers describe only one approach, usually the one they've implemented before, without acknowledging the tradeoffs. A developer who has only done it one way has not had to justify the choice.
2. "How would you handle a payment webhook that might be delivered more than once?"
Idempotency. The answer must include storing a processed event ID before acting, checking it on every incoming webhook, and returning a 200 even on duplicates so the payment provider stops retrying. Developers who say "I'd just process it" have not built a payment flow that survived a duplicate delivery — and every payment provider will eventually send one.
3. "A specific endpoint is slow in production. Walk me through your debugging process."
Strong answers start with measurement: check logs for response time percentiles, add query count logging if not already present, profile in a staging environment with production data volume. The bottleneck is identified before a solution is chosen. Weak answers jump to "I'd add a cache" or "I'd add an index" — which is guessing. Caching a slow query hides the problem; it does not fix it. Indexing the wrong column wastes write performance for no gain.
The right approach with a database bottleneck: run EXPLAIN ANALYZE on the slow query directly in psql, not just in the application. The output shows the query execution plan with actual timing. Seq Scan on a large table means no index matched; Index Scan means one did. Hash Join vs Nested Loop matters too — a nested loop join is O(n×m) where n and m are the row counts of the two tables; a hash join builds a hash table from the smaller relation first and probes it, making it O(n+m). A developer who has never read a query plan cannot diagnose database bottlenecks systematically.
4. "How do you handle a background task that fails halfway through?"
Tests three things in one question: retry logic, idempotency, and dead-letter handling. The answer should describe making the task idempotent first (so retrying it is safe), then configuring automatic retries with exponential backoff (so transient failures recover automatically), then a dead-letter queue or alert for tasks that exhaust retries (so permanently failed tasks are visible, not silently dropped). A developer who describes only retries without idempotency has not thought about what happens when the retry succeeds on the second attempt after a partial first execution.
5. "What's the difference between authentication and authorization, and how have you implemented both?"
Authentication: who are you? Authorization: what are you allowed to do? Conflating the two produces systems that authenticate correctly and then permit everything, or that block authenticated users from legitimate actions. Strong answers describe specific implementations: JWT with expiry for authentication, role-based or permission-based authorization for access control, and why session-based auth is often the better default for server-rendered applications. Weak answers describe only one of the two, or describe them interchangeably.
Red Flags in Portfolios and Code
No tests anywhere in their public repositories. This is not about test coverage percentage — it is about whether tests exist at all. A developer who has never written tests is writing code that is not designed to be maintained or changed safely. The absence of tests in a portfolio is not an oversight; it is a signal about how that developer works.
Hardcoded credentials in GitHub history. Not just in the current code — in the git history. A developer who has committed an API key or database password to a public repository has either not understood the risk or not cared enough to fix it with a history rewrite. Either is a problem on a project where production credentials exist.
No API versioning on any public API work. An API without a version is an API that cannot be changed without breaking clients. If a developer has shipped APIs that other systems consume and has not versioned them, they have either never had to make a breaking change or have not been responsible for the downstream consequences when they did.
"It works on my machine." If a repository has no README, no environment variable documentation, and no instructions for running the project, the developer has not thought about the handoff. For a production project you will maintain and others may work on, this is a proxy for every other handoff: deployment documentation, operational runbooks, and architecture decisions that exist only in the developer's head.
Functions that assume everything succeeds. A get_user(user_id) that does not handle the case where the user does not exist will crash when it encounters one. In production systems, every external call fails sometimes, every database record is occasionally missing, and every queue message is occasionally malformed. A developer who does not write defensive code has not been in production long enough to be bitten by it.
Realistic Rates in 2026
| Experience | India-based | Eastern Europe | US/UK |
|---|---|---|---|
| Mid (3–5 yrs) | $18–35/hr | $35–60/hr | $80–120/hr |
| Senior (6+ yrs) | $30–50/hr | $55–80/hr | $100–160/hr |
For most early-stage products, a senior India-based backend developer at $30–45/hr produces better outcomes than a junior US-based developer at $80/hr — particularly for Python/Django stacks where the Indian talent pool is deep. The lower rate does not mean lower quality; it reflects cost of living, not skill level. The vetting process is what determines quality, not the geography.
Freelancer vs Agency vs Full-Time
Freelancer is the right model for most early-stage projects. Direct communication with the person doing the work, no account manager overhead, full IP ownership from day one. A freelancer on retainer for 20 hours/week is usually more effective than an agency team where you don't know who you'll be working with each sprint.
Agency makes sense when you need design, project management, and development in one contract — and when you cannot provide the project management yourself. The 40–80% agency markup pays for coordination. If you can coordinate the project, you are paying for overhead you do not need.
Full-time hire makes sense once the backend is the core product and you need 40+ hours/week of sustained development with long-term ownership. The overhead of employment — taxes, benefits, HR — rarely makes sense for a first backend build or an MVP.
If you need a backend developer with production experience across Django, REST APIs, PostgreSQL, Celery, and AWS — without the agency overhead — see my rates and availability.
Frequently Asked Questions
How do I evaluate a backend developer if I'm not technical myself? Focus on process signals rather than technical depth. Ask how they've handled a production incident — what went wrong, how they found it, and what they changed afterward. Ask to see a project they've deployed and maintained. The quality of their explanation, the specificity of their examples, and whether they describe their own mistakes honestly are all accessible without a technical background.
Should I hire a specialist (Django, Node, Go) or a generalist backend developer? For most web applications, hire the specialist for your chosen stack. Framework knowledge is not trivially transferable — a Node.js developer switching to Django needs months to develop the ORM, migration, and deployment patterns that a senior Django developer applies automatically. The generalist advantage appears in architectural roles where the choice of stack is still open.
What is a reasonable trial project for a backend developer? A paid task that takes 4–8 hours and requires the skills you will actually need: a small API endpoint with authentication, a background task, and tests. The deliverable should include a README explaining how to run it. You are not evaluating the output alone — you are evaluating the code quality, the tests, the commit history, and the clarity of the setup documentation. All of those reveal working habits that the interview does not.
How many backend developers do I need for an early-stage product? One senior developer can take most early-stage products from zero to production. The argument for two is: redundancy if one is unavailable, and a second opinion on architecture decisions. The argument against: coordination overhead, inconsistent code style, and the cost of two salaries before you have validated the product. Start with one; add the second when the scope genuinely requires it.
What's the difference between a backend developer and a full-stack developer? A backend developer specialises in server-side systems — APIs, databases, background processing, deployment. A full-stack developer covers both backend and frontend. Full-stack is often the right hire for early-stage products where you need one person to own the entire system. Backend specialist makes sense once the frontend complexity is significant enough to warrant dedicated attention, or when the backend itself is the hard part.