Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/LWJGL/lwjgl3/llms.txt

Use this file to discover all available pages before exploring further.

LWJGL 3 is a ground-up redesign that is not backwards compatible with LWJGL 2. The architecture, packaging, windowing model, memory model, and package structure all changed. This page summarises what changed and provides a mapping of common API calls to help you port existing code.
LWJGL 3 cannot be dropped in as a replacement for LWJGL 2. Every call site that touches windowing, input, memory, or callbacks needs to be updated.

Major changes from LWJGL 2

1. Modular packaging

LWJGL 2 was distributed as a single JAR. LWJGL 3 is split into independent modules — one per binding — so you only include what you use. The core module (lwjgl.jar) is required; every binding (GLFW, OpenGL, Vulkan, etc.) is a separate optional artifact. Use the LWJGL build configurator to generate Maven or Gradle declarations for exactly the modules your project needs.

2. Explicit off-heap memory management

LWJGL 2 used BufferUtils.createByteBuffer(), which allocated Java NIO ByteBuffer instances backed by the GC-managed heap. LWJGL 3 exposes a full explicit allocator:
  • MemoryUtil.memAlloc / memFree — Allocate and free off-heap buffers manually. Every allocation must be freed or it leaks.
  • MemoryStack — A thread-local stack allocator for short-lived allocations. Use try-with-resources; the memory is reclaimed automatically when the block exits.
// LWJGL 2 — GC-managed, no free needed
ByteBuffer buf = BufferUtils.createByteBuffer(1024);

// LWJGL 3 — manual allocation
ByteBuffer buf = memAlloc(1024);
try {
    // use buf
} finally {
    memFree(buf);
}

// LWJGL 3 — stack allocation (preferred for short-lived data)
try (MemoryStack stack = stackPush()) {
    ByteBuffer buf = stack.malloc(1024);
    // use buf — freed automatically on block exit
}

3. Windowing moved to GLFW (or SDL)

LWJGL 2 provided its own Display class for window creation and management. LWJGL 3 delegates this to external libraries. GLFW is the most commonly used option and is bundled as the lwjgl-glfw module. SDL 3 is also available as of LWJGL 3.4.0.

4. Input handling through GLFW callbacks

LWJGL 2 provided Keyboard and Mouse classes with polling-style methods. LWJGL 3 uses GLFW callback functions instead. You register a callback once and GLFW calls it when an event fires.

5. New package structure

All LWJGL 3 classes live under org.lwjgl.*. The top-level package hierarchy changed significantly:
LWJGL 2 packageLWJGL 3 package
org.lwjgl.openglorg.lwjgl.opengl (same name, different classes)
org.lwjgl.inputremoved — use org.lwjgl.glfw callbacks
org.lwjgl (Display, etc.)removed — use org.lwjgl.glfw
org.lwjgl.util.*removed or replaced

6. Callbacks are explicit and must be freed

In LWJGL 3, every callback object allocates a native stub. That stub must be freed when it is no longer needed, otherwise it leaks native memory.
GLFWErrorCallback errorCB = GLFWErrorCallback.createPrint(System.err).set();

// On cleanup:
glfwSetErrorCallback(null);
errorCB.free();

7. Library loading via Configuration

LWJGL 2 used System.loadLibrary conventions. LWJGL 3 loads natives from the classpath (from the natives JAR) automatically, and exposes the Configuration class for customisation:
Configuration.LIBRARY_PATH.set("/path/to/natives");

API mapping table

LWJGL 2LWJGL 3
Display.create()glfwCreateWindow(width, height, title, 0, 0)
Display.update()glfwSwapBuffers(window) + glfwPollEvents()
Display.destroy()glfwDestroyWindow(window) + glfwTerminate()
Keyboard.isKeyDown(key)key state via glfwSetKeyCallback or glfwGetKey
Mouse.getDX() / getDY()cursor delta via glfwSetCursorPosCallback
BufferUtils.createByteBuffer(n)MemoryUtil.memAlloc(n) (manual free) or MemoryStack.malloc(n)
BufferUtils.createIntBuffer(n)MemoryUtil.memAllocInt(n) or MemoryStack.mallocInt(n)
GL11.glViewport(...)GL11.glViewport(...) (same call, different import path)
The official wiki has an extended migration guide with more examples: LWJGL3 migration.

Migrating between LWJGL 3.x releases

From 3.3.x to 3.4.x

LWJGL 3.4.0 was released on 2026 Jan 18 and includes the following breaking changes: Removed deprecated struct allocation methods The mallocStack and callocStack methods on all struct classes were removed. These were deprecated in 3.3.0 when shorter malloc and calloc equivalents (without the “Stack” suffix) were introduced. Replace all calls:
// Before (3.3.x)
VkApplicationInfo.mallocStack(stack)

// After (3.4.x)
VkApplicationInfo.malloc(stack)
Removed bindings The following bindings were removed in 3.4.0 and are no longer available:
  • lwjgl-cuda
  • lwjgl-libdivide
  • lwjgl-meow
  • lwjgl-nanovg (Blendish and OUI portions only; NanoVG itself remains)
  • lwjgl-openvr
  • lwjgl-ovr
  • lwjgl-sse
  • lwjgl-tootle
New bindings added in 3.4.0
  • RenderDoc bindings (lwjgl-renderdoc)
  • SDL 3 bindings (lwjgl-sdl)
  • libspng bindings (lwjgl-spng)
FFM backend (JDK 25+) LWJGL 3.4.0 introduces a new backend for downcalls, upcalls, and off-heap memory access based on the JDK Foreign Function & Memory (FFM) API. On JDK 25 or later this backend is enabled by default, making LWJGL fully functional with --sun-misc-unsafe-memory-access=deny. No code changes are required if you do not use internal unsafe APIs. OpenCL cl_ulong constants The carrier type of cl_ulong constants changed from int to long to prevent unintentional sign extension for negative values. Update any comparisons or casts that assumed an int. Vulkan on macOS x64 MoltenVK on x64 now requires macOS 11.0 or later (previously 10.13). API documentation removed from Javadoc LWJGL 3.4.0 no longer includes generated API documentation in javadoc form. Native function signatures for downcalls and upcalls are still present, and each module’s package-info javadoc now links to official API documentation, source repositories, and guides.

From 3.4.0 to 3.4.1

LWJGL 3.4.1 was released on 2026 Feb 03. The breaking changes are limited to the Shaderc and SPIRV Tools bindings:
  • Shaderc/glslang — The resource limits interface (resource_limits_c.h) was extracted into a separate class. A new Configuration.GLSLANG_RESOURCE_LIBRARY_NAME option was added to configure the library path.
  • Shaderc/SPIRV Tools — The optimizer interface was extracted into a separate class. A new Configuration.SPIRV_TOOLS_OPTIMIZER_LIBRARY_NAME option was added.
If you use the Shaderc binding directly (rather than through a higher-level abstraction), update any code that accesses the resource limits or optimizer interfaces to use the new classes.

Build docs developers (and LLMs) love