TL;DR

  1. Current DuckDB main requires C++17 or higher. C++11 is no longer a supported baseline.
  2. This is not only a build-system preference. Common headers already use C++17 features.
  3. The important features are std::string_view, std::optional, if constexpr, type-traits _v helpers, structured bindings, and a small amount of std::variant.

The direct test

DuckDB's Makefile still exposes a CXX_STANDARD override:

ifneq (${CXX_STANDARD}, )
        CMAKE_VARS:=${CMAKE_VARS} -DCMAKE_CXX_STANDARD="${CXX_STANDARD}"
endif

So the direct test is:

CXX_STANDARD=11 GEN=ninja make debug

On the tested DuckDB main snapshot, this fails during CMake configuration:

DuckDB requires C++17 or higher; got CMAKE_CXX_STANDARD=11.
Pass -DCMAKE_CXX_STANDARD=17 (or higher), or unset it to use the default.

The project boundary is explicit. DuckDB accepts C++17, C++20, C++23, and C++26. It does not accept C++11.

Why that boundary exists

The CMake error proves that C++11 is unsupported, but it does not explain why the source wants C++17.

For that, I generated normal C++17 compile commands and rewrote selected real commands to -std=c++11 -fsyntax-only. The first hard errors came from common headers:

src/include/duckdb/common/helper.hpp: error: 'is_same_v' is not a member of 'std'
src/include/duckdb/common/identifier.hpp: error: 'string_view' in namespace 'std' does not name a type
src/include/duckdb/common/optional.hpp: error: 'nullopt' has not been declared in 'std'
src/include/duckdb/common/optional.hpp: error: 'optional' has not been declared in 'std'
src/include/duckdb/common/types/value.hpp: error: 'optional' does not name a type

So this is not a codebase that mostly compiles as C++11. It fails soon after common headers are parsed.

The features are already spread out

A source scan of the same snapshot found these rough counts:

FeatureRough hitsTypical places
if constexpr185casts, aggregates, recursive CTE, template executors
std::string_view / string_view111identifiers, Value, C API v2, settings
std::optional19common optional wrapper, cast/result paths
structured bindings17bind helpers, copy path, function serialization
std::variant1bitpacking compression state

These are better reasons than "modern C++ is nicer".

std::string_view avoids unnecessary string allocation and copying. A database has identifiers, settings, function names, and literal buffers everywhere.

std::optional expresses "there may be no value" without sentinel values, raw pointers, or a separate boolean.

if constexpr matters for DuckDB's template-heavy primitives. A normal if still requires both branches to type-check. if constexpr lets the compiler discard the branch that does not apply to the current type.

The _v type-traits helpers are small but common. C++11 can spell them as std::is_same<T, U>::value, but current DuckDB code is already written in the C++17 form.

Boundary

The claim here is narrow:

C++11 was enough to start the project.
C++17 is now the minimum boundary for expressing and compiling current DuckDB code directly.

This does not mean every C++17 feature is good for database code. It only means the current DuckDB source has crossed the line where C++11 compatibility is still realistic.