RESOURCES · FACTORY PRODUCTION WORKFLOW

How to Produce Factory Commodities Safely in Screeps

Validate an owned active Factory, resolve the COMMODITIES recipe, check all components and output capacity, respect cooldown, match commodity level to the Factory level and PWR_OPERATE_FACTORY effect, submit one reviewed production request, and verify Store deltas afterward.

Verification statusChinese source article: Reviewed in full · Official docs: Checked — produce(), COMMODITIES, cooldown, level, PWR_OPERATE_FACTORY, Store constraints and return codes · Level boundary: Level commodities require a Factory set to the same level by PWR_OPERATE_FACTORY; a Factory level cannot later be changed

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official docs
Checked — produce(), COMMODITIES, cooldown, level, PWR_OPERATE_FACTORY, Store constraints and return codes
Level boundary
Level commodities require a Factory set to the same level by PWR_OPERATE_FACTORY; a Factory level cannot later be changed
Execution boundary
OK means production was scheduled; output and component Store deltas require later verification
JavaScript syntax
Passed
Offline production review
Passed — recipe, components, capacity, cooldown, level, Power effect and one-time request states
Screeps Console test
Pending
Live Factory, Power effect, Store delta and cooldown test
Pending
Last verified
July 26, 2026

Quick answer

Recover one owned active Factory, resolve the requested product through COMMODITIES, require every component amount, enough output capacity, zero cooldown, the correct Factory level, and the required active PWR_OPERATE_FACTORY effect for level commodities. Disable the one-time request before factory.produce(resourceType), then compare output, component Stores, and cooldown afterward.

Read the recipe from COMMODITIES

function getCommodityRecipe(resourceType) {
  if (typeof resourceType !== 'string') {
    return null;
  }

  const recipe = COMMODITIES[resourceType];

  return recipe
    && Number.isInteger(recipe.amount)
    && recipe.amount > 0
    && recipe.components
      ? recipe
      : null;
}

The recipe may include level and cooldown. Use the current constant rather than copying a static table into Memory.

Check every component

function getMissingComponents(factory, recipe) {
  return Object.entries(recipe.components)
    .map(([resourceType, required]) => ({
      resourceType,
      required,
      available:
        factory.store.getUsedCapacity(resourceType)
    }))
    .filter(item => item.available < item.required);
}

The Factory Store is shared by components and products. Component logistics must not remove required inputs after the preflight snapshot.

Check output capacity

function canStoreCommodity(
  factory,
  resourceType,
  amount
) {
  return factory.store.getFreeCapacity(resourceType)
    >= amount;
}

Even with every component present, production fails when the Store cannot receive the recipe output amount.

Match Factory level and Power effect

function getOperateFactoryEffect(factory) {
  return factory.effects?.find(effect =>
    effect.effect === PWR_OPERATE_FACTORY
    && effect.ticksRemaining > 0
  ) ?? null;
}

function hasRequiredFactoryLevel(factory, recipe) {
  if (!Number.isInteger(recipe.level)) {
    return true;
  }

  const effect = getOperateFactoryEffect(factory);

  return factory.level === recipe.level
    && effect?.level === recipe.level;
}

Level-less commodities do not require an operated Factory. Level commodities require both the Factory level and the matching active effect.

Build a testable production plan

function evaluateProduction(factory, resourceType) {
  if (!factory) {
    return { ready: false, reason: 'factory-missing' };
  }

  const recipe = getCommodityRecipe(resourceType);

  if (!recipe) {
    return { ready: false, reason: 'recipe-invalid' };
  }

  if (factory.cooldown > 0) {
    return { ready: false, reason: 'factory-cooling-down', recipe };
  }

  if (!hasRequiredFactoryLevel(factory, recipe)) {
    return { ready: false, reason: 'factory-level-mismatch', recipe };
  }

  const missing = getMissingComponents(factory, recipe);

  if (missing.length > 0) {
    return {
      ready: false,
      reason: 'components-insufficient',
      recipe,
      missing
    };
  }

  if (!canStoreCommodity(
    factory,
    resourceType,
    recipe.amount
  )) {
    return { ready: false, reason: 'output-full', recipe };
  }

  return {
    ready: true,
    reason: 'ready',
    recipe,
    missing: []
  };
}

Complete one-time produce example

State impact: this code may schedule one real Factory production action and writes a request snapshot. It never retries automatically.

function getOwnedActiveFactory(id) {
  const factory = typeof id === 'string'
    ? Game.getObjectById(id)
    : null;

  return factory
    && factory.structureType === STRUCTURE_FACTORY
    && factory.my === true
    && factory.isActive() === true
      ? factory
      : null;
}

module.exports.loop = function () {
  const request = Memory.factoryProduceRequest;

  if (!request || request.enabled !== true) {
    return;
  }

  const factory = getOwnedActiveFactory(request.factoryId);
  const plan = evaluateProduction(
    factory,
    request.resourceType
  );

  request.lastCheckedAt = Game.time;
  request.lastStatus = plan.reason;

  if (!plan.ready) {
    request.preview = {
      missing: plan.missing ?? [],
      recipeLevel: plan.recipe?.level ?? null,
      factoryLevel: factory?.level ?? null,
      cooldown: factory?.cooldown ?? null
    };
    return;
  }

  request.enabled = false;
  request.submittedAt = Game.time;
  request.snapshot = {
    factoryId: factory.id,
    resourceType: request.resourceType,
    outputAmount: plan.recipe.amount,
    outputBefore:
      factory.store.getUsedCapacity(request.resourceType),
    componentsBefore: Object.fromEntries(
      Object.keys(plan.recipe.components).map(type => [
        type,
        factory.store.getUsedCapacity(type)
      ])
    ),
    cooldownBefore: factory.cooldown,
    factoryLevel: factory.level,
    effect: getOperateFactoryEffect(factory)
  };

  const result = factory.produce(request.resourceType);

  request.result = result;
  request.resultAt = Game.time;
  request.status = result === OK
    ? 'accepted-pending-verification'
    : 'failed-review-required';
};

Verify Store and cooldown afterward

function verifyProduction(request) {
  const snapshot = request?.snapshot;
  const factory = getOwnedActiveFactory(
    snapshot?.factoryId
  );

  if (!snapshot || !factory) {
    return { verified: false, reason: 'snapshot-or-factory-missing' };
  }

  const outputNow = factory.store.getUsedCapacity(
    snapshot.resourceType
  );

  return {
    verified:
      request.result === OK
      && outputNow >= snapshot.outputBefore
        + snapshot.outputAmount,
    outputDelta: outputNow - snapshot.outputBefore,
    cooldownNow: factory.cooldown
  };
}

Haulers or another production module can change the Store before verification. Coordinate ownership of Factory actions and component logistics.

Handle return codes

CodeMeaning
OKProduction scheduled
ERR_NOT_ENOUGH_RESOURCESA required component is missing
ERR_INVALID_TARGETThe Factory cannot produce that level commodity
ERR_FULLThe Store cannot receive the product
ERR_INVALID_ARGSThe resource is not a valid commodity
ERR_TIREDThe Factory is cooling down
ERR_RCL_NOT_ENOUGHThe Factory is inactive at the current RCL

Debugging checklist

  • Recover an owned active Factory.
  • Read the current recipe from COMMODITIES.
  • Check every component.
  • Check product capacity.
  • Check cooldown.
  • Match recipe level, Factory level, and active Power effect.
  • Disable before calling.
  • Save component and output snapshots.
  • Record the exact return code.
  • Verify Store delta and cooldown later.

Scope and next steps

This guide does not implement commodity chains, component hauling, Power Creep scheduling, market profitability, multi-Factory allocation, or production forecasting.

Frequently asked questions

Can a level-zero Factory produce level commodities?

No. It needs the matching Factory level and active Power effect.

Can a Factory level be changed?

The official API says it cannot be changed after it is set.

Should a failed production request retry every tick?

No. Review current components, capacity, cooldown, and Power state first.

Does recipe cooldown prove success?

It supports verification, but compare Store deltas as well.

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.