BEGINNER · BUILD AND REPAIR

How to Make a Screeps Creep Build and Repair Automatically

Give Builder1 a clear priority: build owned sites, repair selected damaged structures, and upgrade the Controller when no higher task exists.

Verification statusChinese source: Read in full · Official documentation: Checked · API ranges and codes: Checked

VERIFICATION

Evidence and test status

Chinese source
Read in full
Official documentation
Checked
API ranges and codes
Checked
JavaScript syntax
Checked
Offline priority review
Passed
Screeps Console
Pending
Live multi-tick test
Pending
Last verified
July 24, 2026

Quick answer

Keep Builder1's harvesting state, then give its work phase one clear priority: build the first owned Construction Site, otherwise repair the first selected damaged Structure, otherwise upgrade the Controller. Use return after each selected task so one tick does not continue into lower-priority branches.

The beginner task priority

  1. Build: an owned Construction Site exists.
  2. Repair: no site exists, but a selected Structure has hits < hitsMax.
  3. Upgrade: neither of the first two targets exists.

Priority does not make the Builder universally efficient. It only ensures that one main work action is selected for the current tick.

Which Structures are included in repair?

This lesson repairs:

  • structures that report my === true;
  • Roads;
  • Containers.

It excludes Walls and Ramparts because defensive hit targets need a separate policy. Otherwise one Builder can spend nearly all available Energy on very high hit capacities.

Read-only precheck

State impact: Read-only.

const creep = Game.creeps['Builder1'];

if (!creep) {
  console.log('Builder1 was not found.');
} else {
  const sites =
    creep.room.find(FIND_MY_CONSTRUCTION_SITES);

  const damaged =
    creep.room.find(FIND_STRUCTURES, {
      filter: function (structure) {
        const repairable =
          structure.my === true ||
          structure.structureType === STRUCTURE_ROAD ||
          structure.structureType === STRUCTURE_CONTAINER;

        const excluded =
          structure.structureType === STRUCTURE_WALL ||
          structure.structureType === STRUCTURE_RAMPART;

        return repairable &&
          !excluded &&
          structure.hits < structure.hitsMax;
      }
    });

  console.log(JSON.stringify({
    siteCount: sites.length,
    damagedCount: damaged.length,
    controllerFound: Boolean(creep.room.controller),
    carriedEnergy:
      creep.store.getUsedCapacity(RESOURCE_ENERGY),
    working: creep.memory.working === true
  }));
}

Complete Builder1 priority code

State impact: Calls harvest, build, repair, upgrade, and movement methods, and writes creep.memory.working.

const CREEP_NAME = 'Builder1';

function moveToTarget(creep, target, label) {
  const moveResult = creep.moveTo(target, {
    reusePath: 5
  });

  if (moveResult !== OK &&
      moveResult !== ERR_TIRED) {
    console.log(
      creep.name +
      ' moveTo(' +
      label +
      ') returned ' +
      moveResult +
      '.'
    );
  }
}

module.exports.loop = function () {
  const creep = Game.creeps[CREEP_NAME];

  if (!creep) {
    console.log(
      CREEP_NAME +
      ' was not found. Create it or check the name.'
    );
    return;
  }

  if (creep.spawning) {
    return;
  }

  const source = creep.room.find(FIND_SOURCES)[0];

  if (!source) {
    console.log(
      CREEP_NAME +
      ' cannot find a visible Source.'
    );
    return;
  }

  const usedEnergy =
    creep.store.getUsedCapacity(RESOURCE_ENERGY) || 0;
  const freeEnergy =
    creep.store.getFreeCapacity(RESOURCE_ENERGY) || 0;

  if (usedEnergy === 0) {
    creep.memory.working = false;
  }

  if (freeEnergy === 0) {
    creep.memory.working = true;
  }

  if (!creep.memory.working) {
    const harvestResult = creep.harvest(source);

    if (harvestResult === ERR_NOT_IN_RANGE) {
      moveToTarget(creep, source, 'Source');
    } else if (harvestResult !== OK &&
               harvestResult !== ERR_NOT_ENOUGH_RESOURCES) {
      console.log(
        CREEP_NAME +
        ' harvest() returned ' +
        harvestResult +
        '.'
      );
    }

    return;
  }

  const site =
    creep.room.find(FIND_MY_CONSTRUCTION_SITES)[0];

  if (site) {
    const buildResult = creep.build(site);

    if (buildResult === ERR_NOT_IN_RANGE) {
      moveToTarget(creep, site, 'Construction Site');
    } else if (buildResult !== OK) {
      console.log(
        CREEP_NAME +
        ' build() returned ' +
        buildResult +
        '.'
      );
    }

    return;
  }

  const damaged =
    creep.room.find(FIND_STRUCTURES, {
      filter: function (structure) {
        const repairable =
          structure.my === true ||
          structure.structureType === STRUCTURE_ROAD ||
          structure.structureType === STRUCTURE_CONTAINER;

        const excluded =
          structure.structureType === STRUCTURE_WALL ||
          structure.structureType === STRUCTURE_RAMPART;

        return repairable &&
          !excluded &&
          structure.hits < structure.hitsMax;
      }
    })[0];

  if (damaged) {
    const repairResult = creep.repair(damaged);

    if (repairResult === ERR_NOT_IN_RANGE) {
      moveToTarget(creep, damaged, 'damaged Structure');
    } else if (repairResult !== OK) {
      console.log(
        CREEP_NAME +
        ' repair() returned ' +
        repairResult +
        '.'
      );
    }

    return;
  }

  const controller = creep.room.controller;

  if (!controller) {
    console.log(
      CREEP_NAME +
      ' cannot find a Controller.'
    );
    return;
  }

  const upgradeResult =
    creep.upgradeController(controller);

  if (upgradeResult === ERR_NOT_IN_RANGE) {
    moveToTarget(creep, controller, 'Controller');
  } else if (upgradeResult !== OK) {
    console.log(
      CREEP_NAME +
      ' upgradeController() returned ' +
      upgradeResult +
      '.'
    );
  }
};

Why each task branch returns

Target foundActionContinue to lower priority?
Construction Sitebuild()No
Selected damaged Structurerepair()No
NeitherupgradeController()Final branch

A return means the current tick already has its chosen task. It prevents the same function from continuing into another branch.

Action results to inspect

ResultTypical meaningResponse
ERR_NOT_IN_RANGETarget is farther than the action range.Move toward it.
ERR_NOT_ENOUGH_RESOURCESThe Creep has no carried Energy.Switch back to harvesting.
ERR_NO_BODYPARTNo active WORK remains.Inspect damage.
ERR_INVALID_TARGETThe selected target is no longer valid.Find targets again next tick.
OKThe action was scheduled.Observe later ticks.

build(), repair(), and upgradeController() all have range 3 under the current API.

What to observe

  1. Builder1 harvests when empty.
  2. It builds while any owned site exists.
  3. When no site exists, it selects an allowed damaged Structure.
  4. When neither target exists, it moves to the Controller.
  5. Energy decreases during work.
  6. The Creep returns to the Source when empty.
  7. Only one main task branch runs in the current tick.

Common problems

Walls and Ramparts are never repaired

They are intentionally excluded. Add a separate defensive hit policy later.

The Builder does not choose the nearest target

The code selects the first search result so the article can focus on task priority.

The Creep stands near a target

Inspect the saved action result, carried Energy, active WORK, and target validity.

It upgrades even though you expected repair

Check whether the target passes the ownership, type, exclusion, and hit conditions.

Debugging checklist

  • Confirm Builder1 exists and is not spawning.
  • Confirm a visible Source exists.
  • Inspect memory.working and Store values.
  • Check for owned Construction Sites.
  • Check the repair filter one condition at a time.
  • Confirm Walls and Ramparts are intentionally excluded.
  • Confirm the Controller exists before the fallback action.
  • Save every action and movement result.
  • Verify changed progress or hits on later ticks.

Known limits

  • No nearest-target sorting.
  • No different thresholds for Roads and Containers.
  • No Wall or Rampart hit policy.
  • No multiple-Builder assignment.
  • No target caching or CPU optimization.
  • No automatic Construction Site planning.

Scope and next step

This is a one-Builder learning priority, not a complete maintenance system. Continue with the first room code lesson to combine spawning, harvesting, delivery, upgrading, building, and repair.

Frequently asked questions

Why are Walls and Ramparts excluded?

They need separate target-hit policies.

Why choose only one target?

The lesson explains priority before sorting or assignment.

How close must the Creep be?

Build and repair both work within range 3.

Why upgrade when idle?

It is the final fallback after build and repair targets are absent.

Official documentation

SOURCE AND SCOPE

Review the source, evidence, or next system

This English guide is rewritten for a focused search intent while preserving the technical scope and verification boundaries of its Chinese source. Live-room evidence is claimed only when the verification record says it exists.