Syntax
In short: The formal rules according to which code in a programming language has to be written for it to be valid.
In more detail: Defines how statements, brackets, keywords and structures have to be arranged — regardless of whether the code makes sense in terms of content (that’s semantics). A syntax error (e.g. a missing bracket) prevents code from being compiled or interpreted at all.
In Depth
The difference between syntax and semantics can be shown well with an example:
# Syntactically correct, but semantically nonsensical:
number = "five" + 3
# Syntactically wrong (missing bracket) - won't even start:
print("Hello"The second line is rejected by the interpreter/compiler BEFORE a single command is even executed — a syntax error affects the entire file, not just the faulty spot. The first line, by contrast, is grammatically flawless (an assignment, a + operator between two values), but, depending on the language, leads either to a runtime error or an unexpected result (e.g. "five3" with automatic type coercion).
Every programming language formally defines its own syntax via a grammar (often described in a notation like BNF). A parser checks incoming code against this grammar, before a compiler or interpreter even begins actual processing. IDEs use the same grammar to underline syntax errors in red while you type, long before the code is executed.
Syntax rules differ considerably between languages: Python uses indentation for block structure, C-like languages (Java, C++, JavaScript) use curly braces { }, Lisp dialects almost exclusively use parentheses. Anyone switching between several languages most often confuses exactly these superficial syntactic conventions — the underlying concepts (loops, conditions, functions) are usually much more similar to each other than their respective syntax would suggest.
Syntactic sugar
A related term is “syntactic sugar” — additional syntax variants that don’t bring new functionality, but only express existing constructs more compactly/readably. An example: x += 1 is syntactic sugar for x = x + 1, both produce exactly the same effect, and the shorter notation exists purely for convenience. Modern features like arrow functions in JavaScript (() => {} instead of function() {}) or list comprehensions in Python are also largely syntactic sugar over already-existing functionality.
Syntax highlighting and parser reuse
Editors and IDEs use a language’s same formal grammar for two purposes at once: once to highlight code with colour (keywords, strings, comments in different colours), and once to actually detect syntax errors. Modern tools like Tree-sitter generate a complete syntax tree of the code in real time while typing — the same tree a real compiler/interpreter would later use for processing, just already available in the editor, long before the code is actually executed.
Grammar notation
Formal language grammars are often described in a notation called BNF (Backus-Naur Form) or one of its extensions (EBNF) — a compact, precise notation for specifying which character sequences are syntactically valid. This notation itself isn’t limited to a particular programming language, but is used generally to describe formal languages, even outside programming (e.g. for data formats like JSON, whose specification is also defined in a BNF-like notation).
See also: Code, Pseudocode