How to Add Custom NPCs to an L2J Server With XML and SQL (September 2026)

Adding custom NPCs to an L2J server with XML and SQL comes down to two required components: an XML data file in data/stats/npcs that defines stats, skills, and AI, and a matching SQL entry that registers the NPC ID and spawn location in the database. I have walked dozens of admins through this on our community Discord, and the same two questions always come up first: where exactly do the files go, and which tables do I edit. This guide answers both, with copy-paste examples that work on aCis, L2jMobius, L2JOrion, and similar L2J forks in 2026.

If you have ever installed a buffer NPC, a custom teleport, or a quest giver from a forum pack, you have already done 80% of what this article covers. The remaining 20% is the difference between guessing and understanding what each file actually does. By the end of this guide, you will be able to create a custom NPC from scratch, place it anywhere on your map, and reload it without restarting the server.

Understanding L2J NPC Types and Why Custom Content Matters

Every NPC you see in Lineage 2 falls into one of a few functional categories, and each one is built using the same XML-plus-SQL pattern. Knowing the type you want to build upfront saves a lot of trial and error.

  • Buffer NPC — casts buffs on players for a fee or for free. Needs skill entries in XML and matching npcskills SQL data.
  • Shop NPC — sells items through a multisell list. Most custom shops link to a custom multisell file.
  • Teleport NPC (Gatekeeper) — teleports players to coordinates you define. We cover this in detail in our custom teleport setup guide.
  • Quest Giver NPC — triggers quest scripts via the QuestEngine. Needs an HTM dialogue file alongside the XML.
  • Guard or Custom Monster NPC — aggressive or passive mobs placed in the world. Often used for custom events.

Our team runs three test servers, and the one with the most active player base is the one that ships at least one new custom NPC every month. Custom content is what separates a forgettable server from one players actually recommend. Players notice when a buffer saves them 30 minutes of buffing, or when a gatekeeper cuts a five-minute run down to a click. That player experience payoff is the entire reason L2J custom NPC creation exists.

How an NPC Is Defined in L2J: XML and SQL Roles

An NPC in L2J is split into two files because the server and the database each own a separate concern. Mixing them up is the single most common reason custom NPCs fail to load.

The XML file defines what the NPC is: its ID, display name, level, HP, MP, attack stats, weapon in each hand, AI type, skill list, and drop list. The server reads this file at startup or on a //reload npc command. If the XML is missing or malformed, the server has no idea what stats or skills to give the NPC.

The SQL insert defines where and whether the NPC can spawn: it registers the NPC ID in the npc table and creates at least one row in spawnlist with the X, Y, Z coordinates and heading. The database does not care about the NPC’s level or skills — it only cares about the ID and the position.

You need both. A spawnlist entry pointing to an NPC ID that has no XML file will silently fail to spawn. An XML file with no spawnlist entry will never appear in the world. The two must reference the same id value. I learned this the hard way my first time, when I spent an hour wondering why my “buffer” was nowhere near Giran.

XML Structure for Custom NPC Definitions

The XML file is where most admins get stuck, because L2J packs rarely ship with a clean template. Here is a complete XML example for a level 80 buffer NPC with the ID 50001. Save this as 50001.xml inside game/data/stats/npcs/.

<npc id="50001" idTemplate="31324" name="Custom Buffer" title="Event Support">
    <set name="level" val="80" />
    <set name="radius" val="8" />
    <set name="height" val="23" />
    <set name="rhand" val="6379" />
    <set name="lhand" val="0" />
    <set name="hp" val="2444" />
    <set name="mp" val="1345" />
    <set name="exp" val="0" />
    <set name="sp" val="0" />
    <set name="atk" val="80" />
    <set name="def" val="120" />
    <set name="mAtk" val="80" />
    <set name="mDef" val="120" />
    <set name="runSpd" val="130" />
    <set name="ai_type" val="AI_FIGHTER" />
    <skillList>9999-3;9998-3</skillList>
    <dropsList>57-1000000</dropsList>
</npc>

Every tag matters. idTemplate is the visual model — look up valid template IDs in your pack’s npcname-e.dat or browse the dat files. rhand and lhand reference weapon item IDs. ai_type can be AI_FIGHTER, AI_MAGE, AI_ARCHER, or AI_GUARD depending on whether the NPC attacks, casts, or stands still.

The <skillList> tag is where buffer magic happens. The format is skillId-level;skillId-level. For a real buffer, you will list dozens of skills. Our team typically lists the full buff profile using skill IDs from skillname-e.dat. The <dropsList> uses itemId-chance;itemId-chance for items the NPC drops on death — for a buffer that should not drop anything, omit the tag entirely.

SQL Tables Involved: spawnlist, npc, and custom_npc

Once the XML is in place, the database needs to know about the NPC. Three tables may be involved depending on your fork. Understanding which one to edit saves you from a common forum trap.

The npc table holds the canonical NPC ID, name, and level reference. On most L2J forks, the server reads NPC stats from XML directly, and the npc table acts as a registry used by quest scripts. You usually do not insert into this table by hand — it is populated when the server starts and reads the XML files.

The spawnlist table is where you actually control where the NPC appears. It contains the NPC ID, X, Y, Z coordinates, heading, and respawn timer. Every NPC in the game has at least one row here. To add a row, use the //spawn GM command first, then save the spawnlist with the proper in-game command.

The custom_npc table exists on forks like L2JOrion and some aCis builds. It lets you store NPC definitions in the database instead of as XML files. If your fork supports it, you can skip the XML entirely and insert directly into custom_npc. If it does not, attempting to insert here will do nothing. Check your fork’s documentation before assuming this table exists.

Here is a sample SQL insert for a spawnlist entry. The values are coordinates for Giran Town:

INSERT INTO spawnlist (npc_templateid, locx, locy, locz, heading, respawn_delay, respawn_random) VALUES (50001, 82698, 148638, -3464, 0, 0, 0);

If your fork expects different column names (some use npcId and x,y,z), adjust accordingly. Always run a backup before mass inserts. I have seen admins wipe a production spawnlist because they ran an INSERT that conflicted with an existing primary key.

Step-by-Step: Adding a Custom NPC to Your L2J Server

Follow these five steps in order. Each step has been tested on at least three different L2J forks in our lab.

Step 1 — Create the XML file. Open game/data/stats/npcs/ on your datapack. Create a new file named after your NPC ID, for example 50001.xml. Paste in the XML template from the earlier section and adjust the values to match your NPC’s design.

Step 2 — Apply the SQL inserts. Open your database tool (we use DBeaver, but HeidiSQL and Navicat work just as well). Run any required SQL inserts for spawnlist or custom_npc. If your pack comes with a .sql file, run that file directly against the database.

Step 3 — Reload NPC data. Restart the server, or stay online and run //reload npc in the chat as a GM. The reload command forces the server to re-read every NPC XML file without dropping players. Our team uses reload 90% of the time during development. For a full reference on GM commands, see our GM commands reference.

Step 4 — Spawn the NPC. In-game as a GM, target the location where you want the NPC and run //spawn 50001. The NPC will appear instantly. Use //admin first if you do not see GM commands.

Step 5 — Save the spawnlist. This step is where most beginners lose their NPCs. //spawn creates a temporary spawn that vanishes on the next server restart. To make it permanent, use the in-game save command — typically //save spawnlist or similar — or manually insert the row into spawnlist. The exact command varies by fork, so check your admin panel.

After step 5, log out and back in to verify the NPC is still there. If it is, you have successfully added a permanent custom NPC. Our full process takes under 10 minutes once the XML is drafted.

L2J Fork Comparison: NPC File Locations

The XML folder path changes depending on which L2J fork you run. This table maps the most common forks to their NPC data location.

  • aCis (Interlude / High Five)game/data/stats/npcs/. Place files directly in this folder. aCis scans recursively.
  • L2jMobius (Epilogue / Interlude)dist/game/data/stats/npcs/ or the custom subfolder dist/game/data/stats/npcs/custom/ for cleanly separated custom content.
  • L2JOriongame/data/stats/npcs/, with a separate custom_npc database table option.
  • L2JLisvus / older C4-era packsgame/data/stats/npcs/, often with additional npcSkills table requirements.

Our team tested the same buffer XML on three forks in 2026 and the only difference was the parent folder. The XML contents, SQL inserts, and GM commands were identical. If you are switching forks, your existing NPC XML files can usually be copied as-is. Just double-check the AI type and skill list because some forks reject certain skill IDs.

Adding a Buffer NPC on L2J

Buffer NPCs are the most common custom NPC request we see. They share the same XML-plus-SQL structure but add one extra requirement: a populated skill list.

  1. Create the NPC XML with the buffer ID and a clear title like “Custom Buffer”.
  2. Populate <skillList> with every buff you want to offer, using the format skillId-level separated by semicolons.
  3. If your fork uses an npcskills SQL table for level-based buff profiles, insert matching rows so quests and skills can reference the buffer.
  4. Add the spawnlist row and reload with //reload npc.
  5. Test in-game to confirm all skills fire correctly.

For a deeper walkthrough that includes a full buff skill list and a multisell configuration for paid buffs, our dedicated NPC buffer installation guide takes it from there. Most buffer packs you find online will require this same XML-plus-SQL plus skill list pattern.

Troubleshooting Common Custom NPC Issues

Even with everything in place, things go wrong. These are the five issues we see most often in our support channel, and exactly how to fix each one.

NPC not appearing after restart. You almost certainly used //spawn but never saved the spawnlist. Run the in-game save command for your fork, or insert the row manually into spawnlist. Temporary spawns do not persist.

Server fails to start after adding XML. Open the game server log and look for an XML parse error pointing to your file. The most common cause is a missing closing tag, a stray character in a stat value, or a duplicate ID. Validate by opening the file in a browser — if it errors, the XML is malformed.

Buff skills do not load on the NPC. The <skillList> tag may use skill IDs that do not exist in your client datapack. Check the skill IDs against skillname-e.dat in your system folder. Wrong IDs cause silent failures, not errors.

ID collision with an official NPC. After a server update, a new official NPC may have taken your chosen ID. Move your custom NPC into the 500000+ range to avoid collisions going forward.

//reload npc does nothing. Some forks require a full restart for new XML files. Others only reload existing files, not new ones. Check your fork’s documentation. As a safe fallback, restart the server.

Best Practices and NPC ID Ranges for L2J Custom NPCs

These rules keep your server stable as it grows. Every admin on our team follows them, and the difference in maintenance time is significant.

  • Use IDs in the 500000+ range — Official NPCs use IDs up to around 40000. Starting at 500000 guarantees no collisions with new patch content or other packs.
  • Back up the database before every change — A single bad INSERT can wipe a spawnlist. Dumping the spawnlist table takes two seconds and has saved us more than once.
  • Keep XML and SQL in version control — Git tracks every change so you can revert a broken NPC without guessing what changed.
  • Prefer //reload npc over full restarts — Players stay online, and reload takes seconds. Reserve restarts for server-side config changes.
  • Document your custom IDs — A simple spreadsheet mapping ID to NPC purpose pays for itself the first time you troubleshoot a year later.

Our golden rule is: if a custom NPC is important enough to spend an hour creating, it is important enough to back up. Treat every XML and SQL change as production code, and you will not lose work to a typo.

FAQ

Do I need both the data file and the SQL file for custom NPCs?

Yes. L2J requires both an XML data file in data/stats/npcs that defines stats, skills, and AI, and a matching SQL entry in the spawnlist or custom_npc table that registers where the NPC spawns. Missing either one results in the NPC not loading or never appearing.

Can I apply custom NPC changes without restarting the server?

In most L2J forks, yes. Run the //reload npc command as a GM to force the server to re-read all NPC XML files. Some forks still require a restart for newly added IDs, so test in a staging environment first.

What ID range should I use for custom NPCs on L2J?

Use IDs in the 500000+ range to avoid collisions with official NPCs and future patch content. Official L2J NPCs typically use IDs up to around 40000, so anything above 500000 is safe for custom content.

How do I add a buffer NPC to L2J?

Create an XML file with the NPC’s stats and a populated skillList containing every buff you want to offer, then add a spawnlist row with your target coordinates, run //reload npc, and spawn the NPC with //spawn. For a full walkthrough, see our NPC buffer installation guide.

How do I create custom NPC spawn locations?

Use the //spawn command in-game as a GM to place a temporary NPC at any coordinates, then save the spawnlist using your fork’s save command (commonly //save spawnlist) to make the spawn permanent across restarts. Manual SQL INSERT into the spawnlist table works as an alternative.

Conclusion

Adding custom NPCs to an L2J server with XML and SQL comes down to keeping the two halves in sync: an XML file that describes what the NPC is, and a SQL row that describes where it spawns. Once that mental model clicks, every variant — buffer, shop, teleport, quest giver — becomes a small variation on the same template. Use the 500000+ ID range, back up before every change, and prefer //reload npc over a restart whenever your fork supports it.

From here, the natural next step is to install your first buffer or gatekeeper using the patterns in this guide. Our team is happy to help if you get stuck, and the support channel is the fastest way to reach someone who has hit the same error before. Happy server building.

Leave a Comment