Quick answer: GPU particles require hardware support for compute shaders. Many integrated GPUs, older dedicated cards, and mobile devices do not support them. The particles render fine in the editor because your development machine has a capable GPU, but the exported build may run on hardware that does not.

Here is how to fix Godot particles not showing in exported build. Your particle effects look great in the Godot editor, but after you export the project they vanish entirely. No errors in the console during development, no warnings in the inspector — just invisible particles in the exported build. This is one of the most frustrating Godot 4 issues because it only surfaces after export, and the root causes range from GPU hardware incompatibility to silent resource embedding failures.

Why GPU Particles Disappear on Some Hardware

GPUParticles2D and GPUParticles3D nodes rely on compute shaders to simulate particle behavior on the graphics card. Not all hardware supports compute shaders. Integrated Intel GPUs older than Gen 8, many mobile chipsets, and some budget dedicated GPUs lack the required Vulkan or OpenGL ES 3.1 features. Your development machine almost certainly has a capable GPU, which is why the particles work fine in the editor.

When the exported build runs on unsupported hardware, the GPU particles silently fail to render. Godot does not crash — it simply draws nothing where the particles should be. You can detect this at runtime by checking the rendering capabilities:

# Check if the device supports GPU particles
func _ready():
    var rendering_device = RenderingServer.get_rendering_device()
    if rendering_device == null:
        print("No RenderingDevice available — GPU particles will not work")
        _convert_to_cpu_particles()
    else:
        print("RenderingDevice available: GPU particles supported")

If get_rendering_device() returns null, the hardware does not support the features GPUParticles requires. This is the single most common reason particles disappear in exported builds.

Process Material Not Embedded in the Scene

The second most frequent cause is a ParticleProcessMaterial that is not embedded in the scene file. When you create a GPUParticles2D or GPUParticles3D node and assign a process material through the inspector, the material may be stored as a sub-resource of the scene or as an external .tres file. If it is stored externally and not included in your export filters, the particles will have no material at runtime and will not render.

To check whether the material is embedded, open the scene file (.tscn) in a text editor and look for the ParticleProcessMaterial resource. If it references an external path, make sure that path is included in the export:

# Verify the process material is assigned at runtime
func _ready():
    var particles = $GPUParticles2D
    if particles.process_material == null:
        print("ERROR: No process material assigned to particles!")
        print("The material resource was likely excluded from the export.")
    else:
        print("Process material loaded: ", particles.process_material.resource_path)

The safest fix is to make the material local to the scene. Right-click the material in the inspector and select "Make Unique", then save the scene. This embeds the material directly in the .tscn file so it cannot be excluded from the export.

Particle Shader Compilation Failures

Even when the hardware technically supports GPU particles, the particle shader may fail to compile on the target platform. This happens most often with custom particle shaders or when the Vulkan driver on the target device is outdated. The shader compiles successfully on your development machine but fails silently on the player's device.

Godot 4 introduced shader pre-compilation to mitigate this, but it does not cover every case. You can force shader compilation at load time and catch failures:

# Force shader warm-up and detect compilation issues
func _ready():
    var particles = $GPUParticles3D
    # Emit one frame offscreen to trigger shader compilation
    particles.emitting = true
    await get_tree().process_frame

    # Check if the particles are actually rendering
    if particles.emitting and particles.draw_pass_1 != null:
        print("Particle shader compiled successfully")
    else:
        print("Particle shader may have failed to compile")
        _fallback_to_cpu_particles()

If you are using a custom shader_material on the particle draw pass mesh, test it on every target platform. Driver quirks between vendors (NVIDIA, AMD, Intel, Apple, Qualcomm) can cause identical shader code to behave differently.

Using the Compatibility Renderer as a Fallback

Godot 4 offers three renderers: Forward+, Mobile, and Compatibility. The Compatibility renderer uses OpenGL ES 3.0 instead of Vulkan and has broader hardware support, but it handles GPU particles differently. If you ship your game with the Forward+ renderer and the target hardware does not support Vulkan, particles will not render.

You can configure a renderer fallback in Project Settings so the engine automatically switches to Compatibility mode on unsupported hardware:

# Check which renderer is active and adapt particle strategy
func _ready():
    var renderer = ProjectSettings.get_setting("rendering/renderer/rendering_method")
    print("Active renderer: ", renderer)

    if renderer == "gl_compatibility":
        print("Compatibility mode — GPU particles have limited support")
        _use_cpu_particles()
    else:
        print("Vulkan renderer — full GPU particle support")

In Project Settings, navigate to Rendering > Renderer and note the "Rendering Method" and "Rendering Method.mobile" fields. For maximum compatibility, set the mobile fallback to gl_compatibility. This ensures that when the Forward+ renderer cannot initialize, the engine falls back gracefully instead of rendering blank particles.

CPUParticles2D and CPUParticles3D as a Reliable Alternative

The most reliable fix for particles not showing in exported builds is to replace GPU particle nodes with their CPU equivalents. CPUParticles2D and CPUParticles3D simulate particles on the CPU and render them without compute shaders. They work on every platform and every GPU.

Godot provides a built-in conversion tool. Select your GPUParticles2D or GPUParticles3D node, go to the top menu, and choose GPUParticles2D > Convert to CPUParticles2D (or the 3D equivalent). This copies all your particle settings to a new CPU particle node. You can also do this programmatically as a runtime fallback:

# Runtime fallback: swap GPU particles for CPU particles
func _convert_to_cpu_particles():
    var gpu_particles = $GPUParticles2D
    var cpu_particles = CPUParticles2D.new()

    # Transfer core properties
    cpu_particles.amount = gpu_particles.amount
    cpu_particles.lifetime = gpu_particles.lifetime
    cpu_particles.one_shot = gpu_particles.one_shot
    cpu_particles.explosiveness = gpu_particles.explosiveness
    cpu_particles.position = gpu_particles.position

    # Transfer material properties if available
    var mat = gpu_particles.process_material
    if mat is ParticleProcessMaterial:
        cpu_particles.direction = mat.direction
        cpu_particles.spread = mat.spread
        cpu_particles.initial_velocity_min = mat.initial_velocity_min
        cpu_particles.initial_velocity_max = mat.initial_velocity_max
        cpu_particles.gravity = mat.gravity
        print("Transferred process material properties to CPU particles")

    # Swap the nodes in the tree
    gpu_particles.get_parent().add_child(cpu_particles)
    gpu_particles.queue_free()
    cpu_particles.emitting = true
    print("Switched to CPUParticles2D fallback")

The trade-off is performance: CPU particles are slower than GPU particles for large particle counts (above a few thousand). For most indie game effects — explosions, dust trails, ambient sparkles — the difference is negligible.

Checking Export Logs for Particle Errors

Before any code changes, check the export logs. Godot writes detailed information during the export process that can pinpoint the exact issue. Run the exported build from a terminal to capture standard output:

# Run the exported build from terminal to see logs
# Linux / macOS:
# ./my_game.x86_64 --verbose 2>&1 | tee game_log.txt
# Windows:
# my_game.exe --verbose > game_log.txt 2>&1

# In GDScript, add startup diagnostics
func _ready():
    print("=== Particle Diagnostics ===")
    print("OS: ", OS.get_name())
    print("Video adapter: ", RenderingServer.get_video_adapter_name())
    print("Video adapter vendor: ", RenderingServer.get_video_adapter_vendor())
    print("Rendering method: ", ProjectSettings.get_setting("rendering/renderer/rendering_method"))

    # Log all particle nodes in the scene
    for node in get_tree().get_nodes_in_group("particles"):
        print("Particle node: ", node.name, " | Emitting: ", node.emitting)
        if node is GPUParticles2D or node is GPUParticles3D:
            print("  Type: GPU | Material: ", node.process_material)
        elif node is CPUParticles2D or node is CPUParticles3D:
            print("  Type: CPU")

Look for lines containing SHADER, PARTICLE, or RENDERING in the logs. Common warning messages include "Shader compilation failed", "RenderingDevice not available", and "Material resource not found". These tell you exactly which of the five causes above is responsible.

Related Issues

See also: Fix: Godot Particles Not Emitting.

See also: Fix: Godot Particles2D Not Visible or Not Emitting.

See also: Fix: Godot Shader Pink Magenta Screen.

See also: Fix: Godot Exported Game Missing Resources.

Check the GPU, embed the material, fall back to CPUParticles.