Skip to main content

The finally block

The finally block in a try...catch...finally statement is the part of the error-handling mechanism that runs code in any case, whether an error occurred or not. It closes the statement out: first try, then catch if needed, and finally always last.

Theory

TL;DR

  • finally always runs, after try and after catch.
  • It runs both when try threw an error and when it did not.
  • It runs even when the function already executed a return from try or catch.
  • It runs even when an error was thrown inside catch itself.
  • The typical use is releasing resources and cleaning up state.
  • A return inside finally overwrites the function result, which is bad practice.

Quick example

javascript
try { // code that may throw } catch (error) { // error handling } finally { // code that runs in any case }

How it works step by step

  1. The code inside try runs.
  2. If there is no error in try, catch is skipped and finally runs.
  3. If an error was thrown in try, catch runs and then finally runs.
  4. After finally the program continues.

Example 1. No error, finally still runs:

javascript
try { console.log("try: all good"); } catch (e) { console.log("catch: an error"); } finally { console.log("finally: always runs"); }

Output:

text
try: all good finally: always runs

Example 2. There is an error, finally runs as well:

javascript
try { throw new Error("Failure!"); } catch (e) { console.log("catch:", e.message); } finally { console.log("finally: always runs"); }

Output:

text
catch: Failure! finally: always runs

finally and return

Even when try executes a return, the finally block still runs before the function exits:

javascript
function test() { try { console.log("try"); return "From try"; } catch { console.log("catch"); } finally { console.log("finally"); } } console.log("Result:", test());

Output:

text
try finally Result: From try

But if finally itself contains a return, it overwrites the result from try or catch:

javascript
function test() { try { return "From try"; } finally { return "From finally"; } } console.log(test()); // "From finally"

This is considered bad practice, because it makes the function unpredictable: the value from try silently disappears.

finally when catch throws

finally runs even when a new error was thrown inside catch. The cleanup happens first, and only then the error propagates up the stack:

javascript
try { throw new Error("Error in try"); } catch (e) { console.log("catch:", e.message); throw new Error("Error in catch"); } finally { console.log("finally runs anyway"); }

Output:

text
catch: Error in try finally runs anyway Uncaught Error: Error in catch

A try...finally statement with no catch at all behaves the same way: the error is not intercepted, but the cleanup is guaranteed to happen before it travels further.

Main use cases

Releasing resources:

javascript
try { openConnection(); runQuery(); } catch (e) { console.error("Error:", e); } finally { closeConnection(); // always runs }

Beyond that, finally is used to:

  • clear temporary data and caches;
  • release a lock or a semaphore;
  • stop a timer or cancel a subscription;
  • hide a loading indicator in the UI regardless of how the request ended;
  • finish an operation the same way on success and on failure.

Summary table

BlockWhen it runsPurpose
tryAlwaysCode where an error may happen
catchOnly on an errorException handling
finallyAlwaysCleanup, finishing, releasing resources

Common mistakes

  • return inside finally. It overrides the value from try and catch and can swallow a thrown error, so the function starts lying about its result.
  • Putting code that can itself fail into finally. An error in the cleanup block masks the original error, and you never see the real cause.
  • Believing that finally catches the error. It does not: without a catch the exception keeps propagating up the stack after finally has run.
  • Duplicating the cleanup in try, in catch and in finally. One place is enough, and that is exactly what finally exists for.
  • Putting business logic into finally. It is a teardown block, not a continuation of the scenario, and such functions become hard to read.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.