Top 30 Easy Backend Dev Interview Questions and Answers for Freshers
30 easy multiple-choice Backend Dev interview questions, the ones an interviewer opens with: definitions, everyday syntax, and the quick checks that you have really used it. They come from 30 bites in the Backend Dev library, the gentlest slice of the 533 Backend Dev interview questions in the library. Answer them here or read straight down. Every question carries the correct option, why it is correct, and a link to the bite it came from.
Backend engineering, APIs, and databases
30 questions. Pick an answer, or open “Show the answer” to read it.
Answers are graded in your browser. Nothing is saved, and no XP or streak is earned here. The app keeps score.
Question 1 of 30
When you annotate a FastAPI route parameter with a Pydantic model, what does the framework do with that type hint?
Show the answer
Answer: a · It leverages the hint for automatic request validation and OpenAPI schema generation
FastAPI reads type hints at startup to construct Pydantic models that validate incoming requests and generate OpenAPI schemas automatically. The distractor about runtime enforcement is wrong because Python itself ignores type hints during execution unless an external tool checks them.
Read the full bite: Explain Python type hints and their importance in FastAPI
Question 2 of 30
What is the main reason to place a unique constraint on a non-primary column such as email?
Show the answer
Answer: c · To enforce business-level uniqueness while keeping a stable primary key for joins
The card gives email as an alternate key that stops duplicate signups while the auto-incrementing primary key stays the stable join target. The distractor that it serves as the main row identifier conflates a unique constraint with a primary key, a red flag the card explicitly warns against.
Read the full bite: What is the difference between primary, foreign, and unique keys?
Question 3 of 30
When evaluating a new cloud infrastructure project, which statement accurately reflects the trade-off between using Rust versus Go?
Show the answer
Answer: a · Rust provides deterministic latency and compile-time data-race safety at the cost of a steeper learning curve, whereas Go trades runtime GC overhead for simplicity and faster onboarding.
B is correct because it accurately pairs Rust's deterministic, zero-cost memory safety and compile-time data-race prevention with its steeper learning curve, while recognizing Go's GC introduces runtime overhead in exchange for simplicity and faster onboarding. C is a tempting distractor because Go does automate memory reclamation, but its GC does not prevent data races—memory safety and concurrency safety are distinct, and Go leaves more thread-safety responsibility to the developer.
Question 4 of 30
Which statement best describes how Node.js handles I/O for thousands of concurrent connections?
Show the answer
Answer: a · Network sockets are watched by the OS, while blocking tasks like DNS and file reads use a small internal thread pool.
Node.js relies on the OS kernel to monitor network sockets and notify the event loop when data arrives, while delegating blocking operations like DNS and some file system work to a limited internal thread pool. Distractor D is tempting because Node is famous for non-blocking I/O, but it wrongly assumes every I/O operation can run without thread assistance.
Read the full bite: How does Node.js handle thousands of connections on one thread?
Question 5 of 30
You write an async def FastAPI endpoint that calls requests.get. What is the main risk?
Show the answer
Answer: c · The event loop is blocked, freezing concurrent request handling until the call finishes.
The correct answer is C because calling a blocking library like requests inside async def stalls the event loop, stopping all other requests. The most tempting distractor is A because beginners often assume FastAPI magically threadpools any blocking code, but only def endpoints are run in a threadpool.
Read the full bite: What is the difference between def and async def in Python and FastAPI?
Question 6 of 30
During a bank transfer, if the debit succeeds but the credit fails, which ACID property ensures the money does not vanish?
Show the answer
Answer: b · Atomicity, because the entire transaction must complete or roll back entirely
Atomicity guarantees that a transaction either fully completes or fully rolls back, preventing partial debits without matching credits. Consistency is a tempting distractor because it concerns valid state invariants, not the undo of incomplete operations.
Read the full bite: Explain ACID properties and why they matter for banking or e-commerce
Question 7 of 30
You add a new variant to an error type during a large refactor. Why does Rust typically surface every place needing an update more reliably than Go?
Show the answer
Answer: d · Rust's exhaustive match makes non-updated handling sites fail to compile
Adding an enum variant makes existing exhaustive matches incomplete, so Rust's compiler flags each site. Go's error values do not force callers to branch, so it does not flag missed sites; Rust does not auto-rewrite code.
Read the full bite: Refactoring under Go simplicity versus Rust correctness
Question 8 of 30
When adding a new column to a table and then filling it with values, how do the two types of SQL commands involved differ?
Show the answer
Answer: d · The first command is DDL that modifies the schema and may lock the table, while the second is DML that changes row data inside a transaction
Adding a column is DDL because it changes the schema and often locks the table, while updating rows is DML that operates row by row within a transaction. Option B is tempting because it labels the command types correctly, but it is wrong because DDL often auto-commits and cannot be rolled back in many engines, and DML—not DDL—runs inside explicit transactions.
Read the full bite: What is the difference between DDL and DML in SQL?
Question 9 of 30
If you write let x = 5 in Rust and x := 5 in Go, which statement about mutability is correct?
Show the answer
Answer: c · The Rust declaration is immutable, while the Go declaration allows reassignment without extra keywords
Rust makes bindings immutable by default, so let x = 5 cannot be reassigned without let mut, while Go variables declared with := or var are mutable by default. Option D is a common misconception because both var and := create mutable bindings in Go, and true immutability requires const.
Read the full bite: How does Go's variable declaration and mutability differ from Rust?
Question 10 of 30
Why is it a problem to list a library your source code imports at runtime under devDependencies?
Show the answer
Answer: d · A production install that skips devDependencies leaves it missing, causing runtime errors
Production installs omit devDependencies, so a runtime import placed there will be absent and throw module-not-found. Runtime libraries must live under dependencies.
Read the full bite: dependencies vs devDependencies in package.json
Question 11 of 30
What does Node do first when it encounters require('fs')?
Show the answer
Answer: a · Matches it against built-in core modules, which take precedence
Bare specifiers are checked against built-in core modules first; fs is compiled into the binary and resolves without touching node_modules. The package search only runs for non-core bare names.
Read the full bite: Resolving core vs relative module specifiers
Question 12 of 30
What is the main mechanical difference between Go's for i := 1; i <= 5; i++ and Rust's for i in 1..=5?
Show the answer
Answer: a · Go uses a C-style control statement that manually manages the index, while Rust consumes an iterator hiding index management.
Go's for is a control statement with explicit initialization, condition, and increment, whereas Rust's for consumes an iterator produced by the inclusive range. Option D is a tempting distractor because both loops look similar, but claiming they are semantically identical misses the statement-driven versus iterator-based gap.
Question 13 of 30
When an incoming GET request reaches a FastAPI app, how does @app.get("/") enable the correct function to run?
Show the answer
Answer: d · It registers the function in the app's route table at import time and generates OpenAPI metadata.
The decorator actively registers the function for GET / in the app's internal route table when the module is imported and simultaneously populates the OpenAPI schema, enabling the ASGI layer to dispatch matching requests. Calling it pure syntax sugar is a common misconception because it fundamentally alters the application's routing registry and automatic documentation rather than leaving framework behavior unchanged.
Read the full bite: What is the purpose of @app.get("/") in FastAPI?
Question 14 of 30
Which approach correctly defines a FastAPI endpoint that captures an integer item_id from a URL like /items/42?
Show the answer
Answer: a · Use app.get("/items/{item_id}") and define async def read_item(item_id: int): then use item_id directly inside the function
FastAPI binds curly-braced path segments to function arguments with matching names and type hints, automatically converting and injecting the value. Option B is tempting because the route syntax is correct, but the mismatched argument name breaks the default binding unless you use a Path alias.
Read the full bite: How do you define and access a FastAPI path parameter?
Question 15 of 30
In the normalized design, CustomerName and CustomerAddress are moved out of the Orders table primarily to eliminate which kind of dependency?
Show the answer
Answer: b · A transitive dependency through CustomerID
Customer attributes depend on CustomerID, a non-key column in Orders, so the dependency is transitive and removing it achieves 3NF. A partial dependency would involve only part of a composite primary key, which is a 2NF concern.
Question 16 of 30
Why can't a many-to-many relationship between Students and Courses be modeled with just a single foreign key column on one of those tables?
Show the answer
Answer: c · A single foreign-key column can hold only one related value per row
One foreign-key column stores a single reference per row, so it can only express one side relating to many, not both sides being many. A junction table with two foreign keys is required to represent the full set of pairings.
Read the full bite: Modeling one-to-many versus many-to-many relationships
Question 17 of 30
Which statement about a Promise's state transitions is correct?
Show the answer
Answer: a · Once settled as fulfilled or rejected, the state is permanent and cannot change
Settling is one-way and final; a Promise transitions from pending to exactly one of fulfilled or rejected and stays there. then callbacks run later as microtasks, not synchronously.
Read the full bite: The three states of a JavaScript Promise
Question 18 of 30
Which statement best explains why you must reassign the result of append to the original slice variable in Go?
Show the answer
Answer: d · The append function may allocate a new backing array when capacity is exceeded, so the returned slice header must replace the original variable.
append may allocate an entirely new backing array when capacity is exhausted, so the returned slice header must replace the original variable or data will be lost. The most tempting distractor claims append always modifies in place, which is false and leads to silent bugs when a reallocation occurs.
Read the full bite: How do you append to a Go slice and why reassign?
Question 19 of 30
Given enum WebEvent { PageLoad, PageUnload, KeyPress(char) }, which line correctly instantiates the KeyPress variant with 'q'?
Show the answer
Answer: d · let press = WebEvent::KeyPress('q');
Rust namespaces enum variants under the type with double colons, so WebEvent::KeyPress('q') is correct. WebEvent.KeyPress('q') is invalid because Rust does not use dot notation for enum variants, unlike some other languages.
Read the full bite: Define a WebEvent enum with PageLoad, PageUnload, and KeyPress
Question 20 of 30
If you retrieve a User pointer from a map[int]*User and modify its Name field, what happens?
Show the answer
Answer: a · The change is visible through every reference to that same User struct
Because the map stores pointer addresses, retrieving an entry yields a copy of the pointer that still refers to the same underlying struct; modifying a field therefore affects all references. Option B is tempting because maps do copy values on retrieval, but copying a pointer does not isolate the struct it points to.
Read the full bite: Define a User struct and map of IDs to pointers
Question 21 of 30
Which method correctly enables automatic JSON body validation in a FastAPI route?
Show the answer
Answer: a · Subclass BaseModel and declare it as the type of a path operation function parameter
FastAPI inspects path operation parameter type annotations to automatically parse and validate incoming JSON against a Pydantic BaseModel. Manually calling request.json() bypasses this automatic pipeline, and response_model only defines the outgoing response schema rather than request validation.
Read the full bite: How do you define a Pydantic model for FastAPI request body validation?
Question 22 of 30
Which ACID property guarantees that a committed transaction's effects will survive a server crash that happens immediately after commit?
Show the answer
Answer: c · Durability
Durability ensures committed changes persist to non-volatile storage and survive crashes. Atomicity governs all-or-nothing application before commit, not survival of already-committed data after a crash.
Question 23 of 30
When a FastAPI endpoint receives JSON with extra fields not defined in the Pydantic model, what occurs by default?
Show the answer
Answer: d · Pydantic silently drops the extra fields and the request succeeds
By default Pydantic ignores extra fields, silently dropping them so the model instantiates and the request succeeds. Option C is wrong because that strict 422 behavior only happens when you explicitly configure extra to forbid in model_config.
Read the full bite: How does Pydantic handle extra JSON fields, and how to configure it?
Question 24 of 30
Two requests each read a counter at 10, add one in application code, and write back. The final value is 11. What prevents this lost update most directly?
Show the answer
Answer: b · Performing the increment as a single atomic UPDATE that reads and writes under one lock
An atomic UPDATE counter = counter + 1 reads and writes the row under one lock, so concurrent increments serialize correctly. Merely raising the isolation level does not fix a read-modify-write performed in application code unless it also locks the row.
Question 25 of 30
Two transactions each hold a lock the other needs, forming a cycle. What does a typical database do to recover?
Show the answer
Answer: c · Detect the cycle, abort a chosen victim, and let the application retry
Engines detect the wait-for cycle and roll back one victim to release its locks, then the application retries that transaction. Waiting indefinitely or merging transactions is not how deadlock resolution works.
Read the full bite: Database deadlocks and how engines resolve them
Question 26 of 30
What is the key difference between a Pydantic field defined as name: str = 'guest' and one defined as name: Optional[str] = None?
Show the answer
Answer: d · The first rejects None while the second accepts it, but both may be omitted from input.
Both fields have defaults so neither is required, yet str = 'guest' rejects None while Optional[str] = None accepts it. Distractor A is tempting because Optional sounds optional, but requiredness is determined solely by the presence or absence of a default.
Read the full bite: What is the difference between a Pydantic default and Optional field?
Question 27 of 30
Why is calling fs.readFileSync inside an Express request handler a problem under concurrent load?
Show the answer
Answer: c · It blocks the single event loop thread, stalling all other pending requests
The sync read blocks the one event loop thread until it finishes, so every other request waits. It is not forbidden and does not spawn threads; the async version uses the libuv pool instead.
Question 28 of 30
How do Go and Rust respectively determine whether a function or type is accessible outside its immediate scope?
Show the answer
Answer: c · Go exports identifiers that start with an uppercase letter across packages, while Rust uses the pub keyword to make items visible outside their module.
Go exports uppercase identifiers across packages, while Rust requires explicit pub for module-level visibility. Distractor B is tempting because it correctly names capitalization and pub but wrongly limits Go to file-level scope and Rust to unrestricted crate-wide visibility.
Read the full bite: How do Go and Rust control visibility of functions and types?
Question 29 of 30
What does path.join provide that naive string concatenation of path segments does not?
Show the answer
Answer: c · Platform-correct separators plus normalization of redundant slashes and segments
path.join inserts the right separator per OS and normalizes the path. It does not encrypt, speed up reads, or by itself stop traversal attacks, which still require explicit validation.
Read the full bite: Why use path.join over string concatenation
Question 30 of 30
In module example.com/shop, directory helpers/ contains files with package utils. What is the correct way to import and use ProcessOrder?
Show the answer
Answer: b · Import example.com/shop/helpers and call utils.ProcessOrder
The import path is always the module path plus the subdirectory (helpers), while the package clause (utils) sets the qualifier used in code. Option A is wrong because it assumes the directory name becomes the code qualifier, a common beginner misconception.
Read the full bite: Go package declaration, directory name, and import path relationship
Could you explain these out loud?
That is what an interview actually tests. Tezvyn gives you questions like these with what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.