PHP
Thread Safety
Programming
Web Development
Non-Thread Safety

What is thread safe or non-thread safe in PHP?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Thread Safe (TS) and Non-Thread Safe (NTS) are two build variants of PHP that determine how the interpreter handles concurrent execution. Thread Safe PHP includes internal locking mechanisms that allow it to run safely inside multi-threaded web server processes like Apache with mod_php. Non-Thread Safe PHP omits that locking overhead and is designed for environments where each request runs in its own process, such as PHP-FPM with Nginx or Apache with mod_fcgid.

Choosing the wrong variant does not always produce an obvious error. It can cause subtle data corruption under load in one direction, or unnecessary performance overhead in the other. Knowing which variant your server architecture requires is a prerequisite for a reliable PHP deployment.

What Thread Safety Means in PHP

PHP's thread safety mechanism is called TSRM (Thread Safe Resource Manager), also historically referred to as ZTS (Zend Thread Safety). When PHP is compiled with ZTS enabled, every global variable and internal resource is stored in thread-local storage rather than in a single shared location. This prevents one thread from corrupting another thread's state when multiple threads execute PHP code simultaneously inside the same process.

The cost of TSRM is real. Every access to a global resource goes through an indirection layer that looks up the correct thread-local copy. In benchmarks, ZTS builds of PHP typically run 5-15% slower than NTS builds for the same workload, depending on the application.

php
1// Conceptually, what TSRM does under the hood:
2// Without ZTS:
3//   global $counter;  // one shared location
4//
5// With ZTS:
6//   global $counter;  // resolved to thread-local copy via TSRM lookup

You do not write different PHP code for TS vs NTS builds. The difference is entirely in how the interpreter manages internal state. Your application code is identical.

When to Use Each Variant

The choice depends entirely on how your web server invokes PHP.

Non-Thread Safe (NTS)

Use NTS when PHP runs as a separate process per request. This is the most common production setup today.

Architectures that use NTS:

  • Nginx + PHP-FPM (each FPM worker is a separate process)
  • Apache + mod_fcgid or mod_proxy_fcgi
  • CLI scripts (single process, no threading)
  • Docker containers running PHP-FPM

Since each process handles only one request at a time, there is no shared state between concurrent requests, and thread safety is unnecessary. NTS builds are faster because they skip the TSRM overhead.

Thread Safe (TS)

Use TS when PHP runs inside a multi-threaded web server process where multiple requests are handled by threads sharing the same process memory.

Architectures that use TS:

  • Apache + mod_php on Windows (worker MPM or winnt MPM)
  • IIS + PHP via ISAPI or the FastCGI handler in some configurations
  • Any custom embedding of PHP in a multi-threaded application

On Linux, Apache's prefork MPM spawns separate processes (not threads), so even mod_php with prefork uses process isolation and NTS is safe. The TS requirement mainly applies to Apache's worker or event MPMs with mod_php, and to Windows IIS deployments.

How to Check Your Current PHP Build

bash
php -v

The output includes either NTS or ZTS (which means Thread Safe):

 
PHP 8.3.6 (cli) (built: Apr 11 2024 12:00:00) (NTS)

You can also check programmatically:

php
1<?php
2if (php_sapi_name() === 'cli') {
3    echo "SAPI: CLI\n";
4}
5
6echo "Thread Safety: " . (defined('ZEND_THREAD_SAFE') && ZEND_THREAD_SAFE ? 'Enabled' : 'Disabled') . "\n";
7
8// Or use phpinfo() and look for "Thread Safety => enabled/disabled"
9phpinfo(INFO_GENERAL);

Architecture Comparison

ArchitectureProcess ModelPHP VariantWhy
Nginx + PHP-FPMMulti-process (one request per worker)NTSNo shared memory between workers
Apache prefork + mod_phpMulti-processNTSPrefork uses processes, not threads
Apache worker/event + mod_phpMulti-threadedTSThreads share process memory
Apache + mod_fcgidMulti-process (external PHP)NTSPHP runs in separate processes
IIS + FastCGI (Windows)Depends on configTS (recommended)IIS may use threads internally
CLI scriptsSingle processNTSNo concurrency

PHP Extensions and Thread Safety

Thread safety is not just about the PHP core. Every loaded extension must also be thread-safe for the interpreter to work correctly in a threaded environment. An extension compiled without ZTS support loaded into a ZTS PHP build can cause segfaults or data corruption.

bash
# Check if an extension was compiled with ZTS
php -i | grep "Thread Safety"

Most popular extensions (PDO, mbstring, json, openssl) support both variants. However, some older or niche extensions have only been tested with NTS. If you depend on such an extension, you are effectively locked into NTS and must use a process-based architecture.

Performance Implications

The performance difference between TS and NTS is measurable but not dramatic for most applications. The overhead comes from TSRM's thread-local storage lookups on every internal global access.

 
1Benchmark: Simple request/response cycle (PHP 8.3, same hardware)
2
3NTS (PHP-FPM):   1,247 requests/sec
4TS  (mod_php):   1,089 requests/sec
5
6Difference: ~12.7% throughput reduction with TS

These numbers vary by workload. CPU-heavy applications with many internal state accesses see a larger gap. I/O-bound applications (database queries, API calls) see a smaller gap because the bottleneck is not PHP execution speed.

The practical recommendation: use NTS with PHP-FPM unless your deployment specifically requires a threaded architecture. PHP-FPM is the standard for modern deployments and is what most hosting providers, container images, and cloud platforms configure by default.

Installing the Correct Variant

Linux (Package Manager)

Most Linux package managers install NTS by default. If you use the official PHP packages or Ondrej's PPA, you get NTS.

bash
1# Ubuntu/Debian (NTS by default)
2sudo apt install php8.3-fpm
3
4# Verify
5php -v  # Should show (NTS)

Windows

On Windows, the PHP downloads page (windows.php.net) provides separate ZIP files for TS and NTS. Choose based on your web server:

  • IIS or Apache worker MPM: Download the Thread Safe (TS) version.
  • Apache with mod_fcgid or standalone CLI: Download the Non-Thread Safe (NTS) version.

Docker

Official PHP Docker images use naming conventions to indicate the variant:

dockerfile
1# NTS (FPM) - most common
2FROM php:8.3-fpm
3
4# CLI (NTS)
5FROM php:8.3-cli
6
7# Apache with mod_php (TS on some builds, but typically prefork/NTS)
8FROM php:8.3-apache

Check with php -v inside the container to confirm.

Common Pitfalls

  • Using the TS build with PHP-FPM. PHP-FPM uses process isolation, so thread safety adds overhead without any benefit. Always use NTS with FPM.
  • Using the NTS build with Apache worker/event MPM and mod_php. This can cause random segfaults and data corruption under concurrent load because threads share memory without protection.
  • Assuming TS makes your PHP application code thread-safe. TSRM protects PHP's internal state. It does not make your application logic safe for concurrent access to shared resources like files, databases, or caches. You still need proper locking or transactional logic at the application level.
  • Mixing TS and NTS extensions. Loading an extension compiled for NTS into a ZTS PHP build (or vice versa) typically causes a startup error or a segfault. Always match the extension variant to the PHP variant.
  • Not checking the variant after upgrading PHP. Some upgrade paths or package manager changes can switch the variant silently. Verify with php -v after every major upgrade.
  • Confusing PHP thread safety with application-level concurrency. PHP's request model is fundamentally share-nothing at the application level. Even with TS PHP, each request gets its own variable scope. TS only matters for the interpreter's internal bookkeeping when threads share a process.

Summary

  • Thread Safe (TS/ZTS) PHP uses thread-local storage to protect internal state in multi-threaded server environments. Non-Thread Safe (NTS) PHP skips that overhead.
  • Use NTS with PHP-FPM, Apache prefork, FastCGI, and CLI scripts. Use TS only with Apache worker/event MPM using mod_php or IIS in threaded mode.
  • NTS is faster by roughly 10-15% because it avoids TSRM lookups. Use it unless your server architecture requires threads.
  • Check your build variant with php -v and look for NTS or ZTS in the output.
  • Extensions must match the PHP variant. A TS extension will not load in an NTS build, and vice versa.
  • PHP's thread safety is about the interpreter's internals, not your application code. Application-level concurrency (file locks, database transactions) is a separate concern.

Course illustration
Course illustration

All Rights Reserved.