Skip to content


Circom has static scoping like C and Rust. However, we have that signals and components must have global scoping and hence they should be defined at the top-level block of the template that defines them.

pragma circom 2.0.0;

template Multiplier2 (N) {
   //Declaration of signals.
   signal input in;
   signal output out;

   out <== in;
   signal input x;
   if(N > 0){
    signal output out2;
    out2 <== x;

component main = Multiplier2(5);

Signal out2 must be declared at the top-level block. The next compilation error is produced: "out2 is outside the initial scope".

Regarding visibility, a signal x of component c is also visible in the template t that has declared c, using the notation c.x. No access to signals of nested sub-components is allowed. For instance, if c is built using another component d, the signals of d cannot be accessed from t. This can be seen in the next code:

pragma circom 2.0.0;

template d(){
  signal output x;
  x <== 1;

template c(){
  signal output out2;
  out2 <== 2;
  component comp2 = d();

template t(){
  signal out;
  component c3 = c();
  out <== c3.comp2.x;

component main = t();

This code produces a compilation error since we cannot access comp2 of component c3.

A var can be defined at any block and its visibility is reduced to the block like in C or Rust.