Compiled vs Interpreted Languages: What's the Difference?
The plain-English difference between compiled and interpreted languages, plus how bytecode and JIT compilation sit in between and what it means for speed and workflow.
A compiled language is translated into machine code before it runs, which usually gives faster, self-contained programs. An interpreted language is run by another program that reads and executes the code as it goes, which makes development quicker and code more portable. Most modern languages mix both, using bytecode and just-in-time compilation.
Photo: Unsplash
On this page
- The short answer
- How compilation works
- How interpretation works
- The middle ground: bytecode and virtual machines
- Just-in-time compilation: compiling while the program runs
- Compiled vs interpreted vs JIT compared
- What this means for real projects
- Where to start: choosing based on your needs
- Conclusion
- Sources
If you’ve ever read that “Python is slow because it’s interpreted” or “C++ is fast because it’s compiled”, you’ve met one of the oldest ideas in programming. It’s also one of the most misunderstood. Today, Python compiles to bytecode, JavaScript is compiled while it runs, and Java is a bit of both.
This guide explains what compiled and interpreted really mean, where bytecode and just-in-time (JIT) compilation fit, and how the choice affects speed, deployment and day-to-day development. It’s written for new developers, technical founders and managers who want to understand the trade-offs without a computer science degree.
The short answer
Computers only run machine code, the low-level instructions a specific processor understands. Every programming language needs some way to get from human-readable source code to those instructions.
- Compiled means a program called a compiler translates your entire source code into machine code ahead of time. You ship the result, an executable, and it runs directly on the processor.
- Interpreted means a program called an interpreter reads your code and carries it out as the program runs. You ship the source code (or something close to it), and users need the interpreter installed.
Strictly speaking, being compiled or interpreted is a property of a language’s implementation, not the language itself. There are C interpreters and Python compilers. But each language has a usual way it’s run, and that’s what people mean.
How compilation works
When you compile a program written in C, C++, Rust or Go, the compiler:
- Checks your code for syntax and, in typed languages, type errors.
- Optimizes it, for example by removing unused code or simplifying loops.
- Produces machine code for a specific processor and operating system, such as Windows on x64 or Linux on Arm.
The upside is speed and simplicity at run time. The program starts quickly and doesn’t need extra software on the user’s machine. Many errors are caught before the program ever runs.
The downside is the build step. Every change needs recompiling, which can take a while on big projects, and you need a separate build for each platform you support.
How interpretation works
With an interpreted implementation, you run your source file directly, for example python app.py. The interpreter reads the code and performs each operation.
Python’s own documentation describes Python as an interpreted language, noting that source files can be run directly without first creating an executable. It also says interpreted languages typically have a shorter development and debugging cycle, but programs generally run more slowly.
The upside is a fast feedback loop. Edit a line, run it again, see the result. Interactive shells and notebooks make it easy to explore data or test ideas. The same code runs anywhere the interpreter is installed.
The downside is overhead. The interpreter does extra work on every operation, so CPU-heavy tasks usually run slower than in compiled code. Some errors only appear when that line actually runs.
The middle ground: bytecode and virtual machines
Most popular languages don’t fit neatly in either box. They compile source code into bytecode, a compact set of instructions for a virtual machine rather than a real processor.
- Python. The standard CPython implementation compiles source code into bytecode and caches it in
.pycfiles so the next run can skip that step. The Python virtual machine then executes the bytecode. - Java and Kotlin. The compiler produces bytecode in
.classfiles that run on the Java Virtual Machine (JVM). The same bytecode runs on any operating system with a JVM. - C# and other .NET languages. These compile to an intermediate language (IL) that the .NET runtime turns into machine code.
Bytecode gives you portability, since one build runs on many platforms, while avoiding the cost of re-reading raw source code each time.
Just-in-time compilation: compiling while the program runs
A just-in-time (JIT) compiler turns bytecode or source code into machine code while the program is running, focusing on the parts that run most often. Because it watches the program in action, it can optimize for how the code is actually used.
JavaScript is the best-known example. Google’s V8 engine, used in Chrome and Node.js, starts code in its Ignition bytecode interpreter. Its Sparkplug compiler then quickly turns frequently used code into machine code, and the TurboFan optimizing compiler produces the fastest code for “hot” functions using type information gathered as the code ran. That’s why modern JavaScript is much faster than its interpreted reputation suggests.
Other examples:
- The JVM and .NET runtime use JIT compilers to turn bytecode and IL into optimized machine code.
- Android’s runtime (ART) combines ahead-of-time compilation, JIT compilation and interpretation, and uses profiles of how apps are actually used to decide what to precompile.
- CPython has included an experimental JIT compiler in its main branch since Python 3.13.
- PyPy is an alternative Python implementation built around a JIT compiler.
Going the other way, some runtimes now offer ahead-of-time (AOT) options for languages normally run with a JIT. Microsoft’s .NET Native AOT, for example, compiles an app to native code at publish time. Microsoft says these apps start faster, use less memory and can run without the .NET runtime installed, but they give up features such as dynamic loading and runtime code generation.
Key takeaway: “Compiled vs interpreted” is now a spectrum. The real questions are when translation to machine code happens (before shipping, at startup, or while running) and what that means for your speed, deployment and workflow.
Compiled vs interpreted vs JIT compared
| Ahead-of-time compiled | Interpreted | Bytecode + JIT | |
|---|---|---|---|
| Typical examples | C, C++, Rust, Go, Swift | Shell scripts, Python (CPython runs bytecode in an interpreter) | Java, Kotlin, C#, JavaScript (V8) |
| When code becomes machine code | Before shipping | Never fully; the interpreter executes it | While the program runs |
| Startup time | Fast | Fast to start, slower to run | Can be slower to warm up |
| Peak CPU performance | Usually highest | Usually lowest | Often close to compiled after warm-up |
| What users need installed | Nothing extra | The interpreter | A runtime or virtual machine (unless bundled) |
| Portability | One build per platform | Runs wherever the interpreter does | One build runs on many platforms |
| Feedback loop | Build step on each change | Edit and run immediately | Fast, with a light build step |
| When errors appear | Many at compile time | Many at run time | Mixed, depending on type checking |
What this means for real projects
For most business software, raw language speed isn’t the bottleneck. Web apps, internal tools and APIs usually spend more time waiting on databases, networks and external services than crunching numbers. That’s why interpreted and JIT languages like Python, JavaScript and Ruby power so many successful products.
Compilation choices matter more when you have:
- CPU-heavy work, such as video processing, games, simulations or high-frequency trading.
- Tight startup or memory limits, such as command-line tools, serverless functions or devices with little memory.
- Simple deployment needs, where a single self-contained executable is easier than installing a runtime.
- Safety-critical code, where catching errors before running is a big advantage.
You also don’t have to choose one language for everything. Python’s popular data libraries, for example, call into compiled code for the heavy lifting. Teams often write most of an app in a productive language and move a few hot paths into compiled code.
Where to start: choosing based on your needs
- Start with the job. Web front end means JavaScript or TypeScript. Data analysis usually means Python. iOS means Swift. Systems tools often mean Go or Rust. Our guide to choosing your first programming language goes deeper.
- Check your team’s skills. A language your developers know well beats a faster one they don’t.
- Measure before optimizing. Use a profiler to find the real bottleneck before rewriting anything.
- Consider deployment. If you’ll ship to many machines, think about whether users need a runtime or whether a container solves it. See how to containerize an application.
- Add type checking where it helps. Tools like TypeScript or Python type hints catch some errors earlier without giving up a fast workflow. Compare options in TypeScript vs JavaScript and Python vs JavaScript.
Conclusion
Compiled languages translate code into machine code before it runs, giving speed and self-contained programs at the cost of a build step. Interpreted languages run code through another program, giving a faster feedback loop and portability at some cost to speed. Most modern languages sit in between, using bytecode and JIT compilation to get much of both. For most projects, pick the language that fits the job and your team, then measure performance before worrying about it. For more terms, see our tech glossary.
Sources
- Python documentation: Glossary — definitions of bytecode,
.pyccaching and “interpreted” - V8 blog: Sparkplug, a non-optimizing JavaScript compiler — V8’s Ignition, Sparkplug and TurboFan tiers
- Android Open Source Project: Configure ART — ART’s mix of AOT, JIT and interpretation with profile-guided compilation
- Microsoft Learn: Native AOT deployment overview — .NET ahead-of-time compilation benefits and limitations
- Python Enhancement Proposals: PEP 744, JIT Compilation — CPython’s experimental JIT compiler
Frequently asked questions
What is the main difference between compiled and interpreted languages?
The main difference is when code becomes machine code. A compiled language is translated into machine code before it runs, producing an executable. An interpreted language is executed by another program, the interpreter, as it runs. Compiled programs are usually faster at CPU-heavy work, while interpreted ones usually offer a faster edit-and-run cycle.
Is Python compiled or interpreted?
Python is usually called interpreted, but the standard CPython implementation first compiles source code into bytecode, cached in `.pyc` files. A virtual machine then executes that bytecode. CPython has also included an experimental JIT compiler since Python 3.13, and alternative implementations such as PyPy use JIT compilation. So in practice, Python is a mix.
Is Java compiled or interpreted?
Both. Java source code is compiled into bytecode stored in `.class` files. The Java Virtual Machine then runs that bytecode, using an interpreter at first and a just-in-time compiler to turn frequently used code into optimized machine code. This approach lets the same build run on any operating system with a JVM.
Are compiled languages always faster?
Not always. Ahead-of-time compiled languages like C, C++ and Rust usually lead on raw CPU performance, but JIT-compiled languages like Java, C# and JavaScript can come close once the program has warmed up. For most business apps, speed depends more on databases, network calls and code design than on whether the language is compiled.
What is JIT compilation?
JIT, or just-in-time, compilation turns code into machine code while a program is running. The runtime watches which parts run most often and optimizes those, sometimes using information about how the code is actually used. JavaScript engines like V8, the Java Virtual Machine and the .NET runtime all use JIT compilers.
Is JavaScript an interpreted language?
It's traditionally described as interpreted, but modern engines compile it. Google's V8 engine, used in Chrome and Node.js, first runs code in a bytecode interpreter, then compiles frequently used code to machine code with its Sparkplug and TurboFan compilers. That's a big reason JavaScript performance has improved so much.
Should beginners learn a compiled or interpreted language first?
Most beginners do well starting with Python or JavaScript, which are interpreted or JIT-compiled and give fast feedback. You can run small pieces of code and see results right away. Learn a compiled language like C, Go or Rust later to understand memory, types and performance more deeply. Choose based on what you want to build.
Was this guide useful
No reviews yet. Share your experience and help other readers.