Opentrons Temperature Module - precise heating and cooling (4-95°C) for sample storage, enzyme reactions, and temperature-sensitive protocols with aluminum block adapters for plates, tubes, and PCR strips
The Opentrons Temperature Module provides precise temperature control (4-95°C) for maintaining samples at specific temperatures during automated protocols. Ideal for keeping reagents cold, pre-warming reaction components, temperature-sensitive incubations, and any workflow requiring stable thermal conditions without mixing.
Core value: Eliminate ice buckets and water baths. Maintain precise, reproducible temperatures on-deck for reagents, samples, and reaction components throughout your protocol.
Use the Temperature Module skill when:
Don't use when:
| Operation | Method | Key Parameters |
|---|---|---|
| Load module | protocol.load_module() | "temperature module gen2", location |
| Set temperature | set_temperature() | celsius (4-95) |
| Get current temperature | .temperature | Read-only property |
| Check status | .status | Returns "holding at target" or "idle" |
| Deactivate | deactivate() | - |
Both Opentrons Flex and OT-2
Key GEN2 improvements:
from opentrons import protocol_api
metadata = {'apiLevel': '2.19'}
def run(protocol: protocol_api.ProtocolContext):
# Load Temperature Module GEN2
temp_mod = protocol.load_module("temperature module gen2", "D1") # Flex
# temp_mod = protocol.load_module("temperature module gen2", "4") # OT-2
# Load labware on module
cold_plate = temp_mod.load_labware("opentrons_96_aluminumblock_generic_pcr_strip_200ul")
Module versions:
"temperature module gen2" - GEN2 (recommended)"temperatureModuleV1" - GEN1 (legacy)Deck slot: Any compatible slot (Flex: A1-D3, OT-2: 1-11)
Recommended approach - Load adapter first, then labware:
# 96-well aluminum block
temp_block = temp_mod.load_adapter("opentrons_96_well_aluminum_block")
sample_plate = temp_block.load_labware("opentrons_96_wellplate_200ul_pcr_full_skirt")
Available adapters:
| Adapter Name | Compatible Labware |
|---|---|
opentrons_96_well_aluminum_block | 96-well plates, PCR plates |
opentrons_aluminum_flat_bottom_plate | Flat-bottom plates |
opentrons_96_deep_well_temp_mod_adapter | Deep-well plates |
For tube racks with aluminum blocks:
# 24-well block with various tube types
tubes_nest = temp_mod.load_labware("opentrons_24_aluminumblock_nest_1.5ml_snapcap")
tubes_generic = temp_mod.load_labware("opentrons_24_aluminumblock_generic_2ml_screwcap")
# Pre-configured combinations (older API versions)
plate_combo = temp_mod.load_labware("opentrons_96_aluminumblock_biorad_wellplate_200ul")
Recommendation: Use standalone adapters (API 2.15+) for better flexibility.
# Set temperature and wait until reached
temp_mod.set_temperature(celsius=4)
# Protocol waits here until 4°C is reached
# Perform operations at target temperature
pipette.transfer(100, cold_reagent, dest_plate.wells())
Temperature range: 4-95°C (1°C resolution)
Behavior: Protocol execution blocks (waits) until target temperature is reached.
# Get current temperature
current_temp = temp_mod.temperature
protocol.comment(f"Module at {current_temp}°C")
# Check status
status = temp_mod.status
# Returns: "holding at target" or "idle"
if status == "holding at target":
protocol.comment("Temperature stable, proceeding")
# Turn off temperature control
temp_mod.deactivate()
Important: Module does not automatically deactivate at protocol end. Must be manually turned off via Opentrons App if protocol completes or is cancelled.
# Keep enzymes and master mix cold throughout protocol
temp_mod = protocol.load_module("temperature module gen2", "D1")
reagent_block = temp_mod.load_adapter("opentrons_24_aluminumblock_nest_1.5ml_snapcap")
# Set to 4°C before starting
temp_mod.set_temperature(4)
# Reagents stay cold during entire protocol
pipette.transfer(10, reagent_block["A1"], dest_plate.wells())
# ... rest of protocol ...
# Turn off at end
temp_mod.deactivate()
# Pre-warm buffer to 37°C
temp_mod = protocol.load_module("temperature module gen2", "C2")
warm_block = temp_mod.load_adapter("opentrons_96_well_aluminum_block")
warm_plate = warm_block.load_labware("corning_96_wellplate_360ul_flat")
# Set to reaction temperature
temp_mod.set_temperature(37)
# Use pre-warmed components
pipette.transfer(50, warm_plate["A1"], reaction_plate.wells())
temp_mod.deactivate()
# Cool samples after PCR or heat inactivation
temp_mod = protocol.load_module("temperature module gen2", "D3")
cooling_block = temp_mod.load_adapter("opentrons_96_well_aluminum_block")
# Set to 4°C for cooling
temp_mod.set_temperature(4)
# Move hot samples to cooling block with gripper (Flex)
protocol.move_labware(hot_plate, temp_mod, use_gripper=True)
# Hold at 4°C
protocol.delay(minutes=5)
# Continue processing cooled samples
temp_mod.deactivate()
# Restriction digest at optimal temperature
temp_mod = protocol.load_module("temperature module gen2", "D1")
rxn_block = temp_mod.load_adapter("opentrons_96_well_aluminum_block")
rxn_plate = rxn_block.load_labware("opentrons_96_wellplate_200ul_pcr_full_skirt")
# Setup reaction
pipette.transfer(20, dna_samples, rxn_plate.wells()[:8])
pipette.transfer(5, enzyme_mix, rxn_plate.wells()[:8], mix_after=(3, 15))
# Incubate at optimal temperature
temp_mod.set_temperature(37)
protocol.delay(hours=2)
# Heat inactivation
temp_mod.set_temperature(65)
protocol.delay(minutes=20)
# Cool for downstream processing
temp_mod.set_temperature(4)
temp_mod.deactivate()
# Keep samples at 4°C except during specific steps
cold_storage = protocol.load_module("temperature module gen2", "D1")
cold_block = cold_storage.load_adapter("opentrons_96_well_aluminum_block")
sample_plate = cold_block.load_labware("biorad_96_wellplate_200ul_pcr")
# Set to 4°C at start
cold_storage.set_temperature(4)
# Samples stay cold on module
# Move to room temp for specific operations
protocol.move_labware(sample_plate, "C2", use_gripper=True)
# ... perform room-temp operations ...
# Return to cold storage
protocol.move_labware(sample_plate, cold_storage, use_gripper=True)
cold_storage.deactivate()
# Pre-cool samples before PCR
temp_mod = protocol.load_module("temperature module gen2", "D1")
tc_mod = protocol.load_module("thermocyclerModuleV2")
cold_block = temp_mod.load_adapter("opentrons_96_well_aluminum_block")
sample_plate = cold_block.load_labware("opentrons_96_wellplate_200ul_pcr_full_skirt")
# Keep samples cold
temp_mod.set_temperature(4)
# Setup PCR mix (samples stay cold)
# ... pipetting ...
# Transfer to thermocycler
tc_mod.open_lid()
protocol.move_labware(sample_plate, tc_mod, use_gripper=True)
# Run PCR
tc_mod.close_lid()
# ... thermal cycling ...
# Return to cold storage after PCR
tc_mod.open_lid()
protocol.move_labware(sample_plate, temp_mod, use_gripper=True)
temp_mod.deactivate()
# Cool after shaking/heating
hs_mod = protocol.load_module("heaterShakerModuleV1", "D1")
temp_mod = protocol.load_module("temperature module gen2", "D2")
# Pre-cool temperature module
temp_mod.set_temperature(4)
# Heat/shake on heater-shaker
hs_mod.set_and_wait_for_temperature(65)
hs_mod.close_labware_latch()
hs_mod.set_and_wait_for_shake_speed(1000)
protocol.delay(minutes=10)
hs_mod.deactivate_shaker()
hs_mod.deactivate_heater()
hs_mod.open_labware_latch()
# Transfer to temperature module for cooling
protocol.move_labware(reaction_plate, temp_mod, use_gripper=True)
protocol.delay(minutes=3)
temp_mod.deactivate()
# Temperature-controlled magnetic separation
mag_block = protocol.load_module("magneticBlockV1", "D1")
temp_mod = protocol.load_module("temperature module gen2", "D2")
# Cool elution buffer
temp_mod.set_temperature(4)
# Magnetic separation
protocol.move_labware(sample_plate, mag_block, use_gripper=True)
protocol.delay(minutes=3)
pipette.transfer(150, sample_plate.wells(), waste.wells())
# Elute with cold buffer
protocol.move_labware(sample_plate, temp_mod, use_gripper=True)
pipette.transfer(50, cold_buffer, sample_plate.wells())
temp_mod.deactivate()
❌ Pipetting during temperature change:
temp_mod.set_temperature(4)
# set_temperature() blocks until reached, but safer to check status
pipette.transfer(...) # Risk if not fully stabilized
✅ Correct:
temp_mod.set_temperature(4)
# Wait for status confirmation
if temp_mod.status == "holding at target":
pipette.transfer(...)
❌ Not deactivating module:
temp_mod.set_temperature(4)
# ... protocol ends ...
# Module stays at 4°C indefinitely!
✅ Correct:
temp_mod.set_temperature(4)
# ... operations ...
temp_mod.deactivate()
❌ Temperature out of range:
temp_mod.set_temperature(100) # Error: max is 95°C
temp_mod.set_temperature(0) # Error: min is 4°C
✅ Correct:
temp_mod.set_temperature(95) # Within range
temp_mod.set_temperature(4) # Within range
❌ Loading labware before temperature stabilizes:
temp_mod.set_temperature(4)
# Temperature not yet reached - samples warm during cooling
pipette.transfer(100, warm_samples, temp_block.wells())
✅ Correct:
# Set temperature BEFORE loading samples
temp_mod.set_temperature(4)
# Now at 4°C, samples stay cold
pipette.transfer(100, warm_samples, temp_block.wells())
Module not reaching 4°C:
Module not reaching high temperatures:
Temperature not stable:
Slow temperature changes:
Module stays on after protocol:
deactivate() to protocol end| Parameter | Minimum | Maximum | Resolution |
|---|---|---|---|
| Block temperature | 4°C | 95°C | 1°C |
| Cooling capacity | ~4°C below ambient | - | - |
| Heating capacity | - | 95°C | - |
Note: Actual minimum temperature depends on ambient conditions. In warm room (>25°C), reaching 4°C may be difficult.
# Ramp temperature for optimization
temp_mod = protocol.load_module("temperature module gen2", "D1")
for temp in [4, 20, 37, 55, 70]:
temp_mod.set_temperature(temp)
protocol.comment(f"Now at {temp}°C")
# Perform operations at each temperature
# ... sampling, measurements, etc. ...
protocol.delay(minutes=5)
temp_mod.deactivate()
# Maintain two different temperatures simultaneously
cold_mod = protocol.load_module("temperature module gen2", "D1")
warm_mod = protocol.load_module("temperature module gen2", "D2")
cold_mod.set_temperature(4)
warm_mod.set_temperature(37)
# Use both temperature zones in protocol
pipette.transfer(10, cold_mod.labware["A1"], reaction_plate.wells())
pipette.transfer(50, warm_mod.labware["A1"], reaction_plate.wells())
cold_mod.deactivate()
warm_mod.deactivate()
# Quick temperature changes for cell work
temp_mod = protocol.load_module("temperature module gen2", "D1")
cell_plate = temp_mod.load_labware("corning_96_wellplate_360ul_flat")
# Ice incubation
temp_mod.set_temperature(4)
protocol.delay(minutes=20)
# Heat shock
temp_mod.set_temperature(42)
protocol.delay(seconds=45)
# Recovery
temp_mod.set_temperature(37)
protocol.delay(minutes=5)
temp_mod.deactivate()
| Feature | GEN1 | GEN2 |
|---|---|---|
| Temperature range | 4-95°C | 4-95°C |
| Cooling | Basic | Improved with insulation |
| Thermocycler compatibility | Poor cooling | Good cooling |
| Plate insulation | None | Plastic shroud |
| Block shrouds | No | Yes |
| API | Same | Same |
| Recommended | No | Yes |
Recommendation: Use GEN2 for all new protocols.
opentrons - Main Opentrons Python API skillopentrons-heater-shaker - Temperature control with mixing (37-95°C)opentrons-thermocycler - PCR thermal cycling (4-99°C block)opentrons-gripper - Automated labware movement (Flex)opentrons-magnetic-block - Magnetic bead separation