diff --git a/src/Config/InputObjectTypeDefinition.php b/src/Config/InputObjectTypeDefinition.php
index 5ed2fd46c..1453467ae 100644
--- a/src/Config/InputObjectTypeDefinition.php
+++ b/src/Config/InputObjectTypeDefinition.php
@@ -5,6 +5,7 @@
 namespace Overblog\GraphQLBundle\Config;
 
 use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
+use Symfony\Component\Config\Definition\Builder\VariableNodeDefinition;
 
 use function is_string;
 
@@ -31,6 +32,7 @@ public function getDefinition(): ArrayNodeDefinition
                         ->append($this->typeSection(true))
                         ->append($this->descriptionSection())
                         ->append($this->defaultValueSection())
+                        ->append($this->publicSection())
                         ->append($this->validationSection(self::VALIDATION_LEVEL_PROPERTY))
                         ->append($this->deprecationReasonSection())
                     ->end()
@@ -42,4 +44,10 @@ public function getDefinition(): ArrayNodeDefinition
 
         return $node;
     }
+
+    protected function publicSection(): VariableNodeDefinition
+    {
+        return self::createNode('public', 'variable')
+            ->info('Visibility control to field (expression language can be used here)');
+    }
 }
diff --git a/src/Config/Parser/MetadataParser/MetadataParser.php b/src/Config/Parser/MetadataParser/MetadataParser.php
index 6e2878ece..91dce00d4 100644
--- a/src/Config/Parser/MetadataParser/MetadataParser.php
+++ b/src/Config/Parser/MetadataParser/MetadataParser.php
@@ -645,9 +645,14 @@ private static function getGraphQLInputFieldsFromMetadatas(ReflectionClass $refl
 
             /** @var Metadata\Field|null $fieldMetadata */
             $fieldMetadata = self::getFirstMetadataMatching($metadatas, Metadata\Field::class);
+            $publicMetadata = self::getFirstMetadataMatching($metadatas, Metadata\IsPublic::class);
 
             // No field metadata found
             if (null === $fieldMetadata) {
+                if (null !== $publicMetadata) {
+                    throw new InvalidArgumentException(sprintf('The metadatas %s defined on "%s" are only usable in addition of metadata %s', self::formatMetadata('Visible'), $reflector->getName(), self::formatMetadata('Field')));
+                }
+
                 continue;
             }
 
@@ -678,6 +683,10 @@ private static function getGraphQLInputFieldsFromMetadatas(ReflectionClass $refl
                 $fieldConfiguration['type'] = $fieldType;
             }
 
+            if ($publicMetadata) {
+                $fieldConfiguration['public'] = self::formatExpression($publicMetadata->value);
+            }
+
             $fieldConfiguration = array_merge(self::getDescriptionConfiguration($metadatas, true), $fieldConfiguration);
             $fields[$fieldName] = $fieldConfiguration;
         }
diff --git a/src/Definition/Builder/SchemaBuilder.php b/src/Definition/Builder/SchemaBuilder.php
index aee461512..8f35b33a5 100644
--- a/src/Definition/Builder/SchemaBuilder.php
+++ b/src/Definition/Builder/SchemaBuilder.php
@@ -10,12 +10,14 @@
 use Overblog\GraphQLBundle\Definition\Type\SchemaExtension\ValidatorExtension;
 use Overblog\GraphQLBundle\Resolver\TypeResolver;
 
+use Symfony\Contracts\Service\ResetInterface;
 use function array_map;
 
-final class SchemaBuilder
+final class SchemaBuilder implements ResetInterface
 {
     private TypeResolver $typeResolver;
     private bool $enableValidation;
+    private array $builders = [];
 
     public function __construct(TypeResolver $typeResolver, bool $enableValidation = false)
     {
@@ -23,22 +25,21 @@ public function __construct(TypeResolver $typeResolver, bool $enableValidation =
         $this->enableValidation = $enableValidation;
     }
 
-    public function getBuilder(string $name, ?string $queryAlias, string $mutationAlias = null, string $subscriptionAlias = null, array $types = []): Closure
+    public function getBuilder(string $name, ?string $queryAlias, string $mutationAlias = null, string $subscriptionAlias = null, array $types = [], bool $resettable = false): Closure
     {
-        return function () use ($name, $queryAlias, $mutationAlias, $subscriptionAlias, $types): ExtensibleSchema {
-            static $schema = null;
-            if (null === $schema) {
-                $schema = $this->create($name, $queryAlias, $mutationAlias, $subscriptionAlias, $types);
+        return function () use ($name, $queryAlias, $mutationAlias, $subscriptionAlias, $types, $resettable): ExtensibleSchema {
+            if (!isset($this->builders[$name])) {
+                $this->builders[$name] = $this->create($name, $queryAlias, $mutationAlias, $subscriptionAlias, $types, $resettable);
             }
 
-            return $schema;
+            return $this->builders[$name];
         };
     }
 
     /**
      * @param string[] $types
      */
-    public function create(string $name, ?string $queryAlias, string $mutationAlias = null, string $subscriptionAlias = null, array $types = []): ExtensibleSchema
+    public function create(string $name, ?string $queryAlias, string $mutationAlias = null, string $subscriptionAlias = null, array $types = [], bool $resettable = false): ExtensibleSchema
     {
         $this->typeResolver->setCurrentSchemaName($name);
         $query = $this->typeResolver->resolve($queryAlias);
@@ -46,6 +47,7 @@ public function create(string $name, ?string $queryAlias, string $mutationAlias
         $subscription = $this->typeResolver->resolve($subscriptionAlias);
 
         $schema = new ExtensibleSchema($this->buildSchemaArguments($name, $query, $mutation, $subscription, $types));
+        $schema->setIsResettable($resettable);
         $extensions = [];
 
         if ($this->enableValidation) {
@@ -74,4 +76,12 @@ private function buildSchemaArguments(string $schemaName, Type $query, ?Type $mu
             },
         ];
     }
+
+    public function reset(): void
+    {
+        $this->builders = array_filter(
+            $this->builders,
+            fn (ExtensibleSchema $schema) => false === $schema->isResettable()
+        );
+    }
 }
diff --git a/src/Definition/Type/ExtensibleSchema.php b/src/Definition/Type/ExtensibleSchema.php
index 79b84ce7b..e8b267975 100644
--- a/src/Definition/Type/ExtensibleSchema.php
+++ b/src/Definition/Type/ExtensibleSchema.php
@@ -10,6 +10,11 @@
 
 class ExtensibleSchema extends Schema
 {
+    /**
+     * Need to reset when container reset called
+     */
+    private bool $isResettable = false;
+
     public function __construct($config)
     {
         parent::__construct(
@@ -51,4 +56,14 @@ public function processExtensions()
 
         return $this;
     }
+
+    public function isResettable(): bool
+    {
+        return $this->isResettable;
+    }
+
+    public function setIsResettable(bool $isResettable): void
+    {
+        $this->isResettable = $isResettable;
+    }
 }
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index a8c4c707e..5ea7c527c 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -218,6 +218,7 @@ private function definitionsSchemaSection(): ArrayNodeDefinition
                     ->scalarNode('query')->defaultNull()->end()
                     ->scalarNode('mutation')->defaultNull()->end()
                     ->scalarNode('subscription')->defaultNull()->end()
+                    ->scalarNode('resettable')->defaultFalse()->end()
                     ->arrayNode('types')
                         ->defaultValue([])
                         ->prototype('scalar')->end()
diff --git a/src/DependencyInjection/OverblogGraphQLExtension.php b/src/DependencyInjection/OverblogGraphQLExtension.php
index 257952eef..c48343a3f 100644
--- a/src/DependencyInjection/OverblogGraphQLExtension.php
+++ b/src/DependencyInjection/OverblogGraphQLExtension.php
@@ -245,6 +245,7 @@ private function setSchemaArguments(array $config, ContainerBuilder $container):
                 $schemaConfig['mutation'],
                 $schemaConfig['subscription'],
                 $schemaConfig['types'],
+                $schemaConfig['resettable'],
             ]);
             // schema
             $schemaID = sprintf('%s.schema_%s', $this->getAlias(), $schemaName);
diff --git a/src/Request/Executor.php b/src/Request/Executor.php
index 706cd4fa1..4c808a2ae 100644
--- a/src/Request/Executor.php
+++ b/src/Request/Executor.php
@@ -13,6 +13,7 @@
 use GraphQL\Validator\Rules\DisableIntrospection;
 use GraphQL\Validator\Rules\QueryComplexity;
 use GraphQL\Validator\Rules\QueryDepth;
+use Overblog\GraphQLBundle\Definition\Type\ExtensibleSchema;
 use Overblog\GraphQLBundle\Event\Events;
 use Overblog\GraphQLBundle\Event\ExecutorArgumentsEvent;
 use Overblog\GraphQLBundle\Event\ExecutorContextEvent;
@@ -21,15 +22,21 @@
 use RuntimeException;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
-
+use Symfony\Contracts\Service\ResetInterface;
 use function array_keys;
-use function is_callable;
 use function sprintf;
 
-class Executor
+class Executor implements ResetInterface
 {
     public const PROMISE_ADAPTER_SERVICE_ID = 'overblog_graphql.promise_adapter';
 
+    /**
+     * @var array<Closure>
+     */
+    private array $schemaBuilders = [];
+    /**
+     * @var array<Schema>
+     */
     private array $schemas = [];
     private EventDispatcherInterface $dispatcher;
     private PromiseAdapter $promiseAdapter;
@@ -61,7 +68,7 @@ public function setExecutor(ExecutorInterface $executor): self
 
     public function addSchemaBuilder(string $name, Closure $builder): self
     {
-        $this->schemas[$name] = $builder;
+        $this->schemaBuilders[$name] = $builder;
 
         return $this;
     }
@@ -75,7 +82,7 @@ public function addSchema(string $name, Schema $schema): self
 
     public function getSchema(string $name = null): Schema
     {
-        if (empty($this->schemas)) {
+        if (empty($this->schemaBuilders) && empty($this->schemas)) {
             throw new RuntimeException('At least one schema should be declare.');
         }
 
@@ -83,22 +90,35 @@ public function getSchema(string $name = null): Schema
             $name = isset($this->schemas['default']) ? 'default' : array_key_first($this->schemas);
         }
 
-        if (!isset($this->schemas[$name])) {
-            throw new NotFoundHttpException(sprintf('Could not find "%s" schema.', $name));
+        if (null === $name) {
+            $name = isset($this->schemaBuilders['default']) ? 'default' : array_key_first($this->schemaBuilders);
         }
 
-        $schema = $this->schemas[$name];
-        if (is_callable($schema)) {
-            $schema = $schema();
+        if (isset($this->schemas[$name])) {
+            $schema = $this->schemas[$name];
+        } elseif (isset($this->schemaBuilders[$name])) {
+            $schema = call_user_func($this->schemaBuilders[$name]);
+
             $this->addSchema((string) $name, $schema);
+        } else {
+            throw new NotFoundHttpException(sprintf('Could not find "%s" schema.', $name));
         }
 
         return $schema;
     }
 
+    public function reset(): void
+    {
+        // Remove only ExtensibleSchema and isResettable
+        $this->schemas = array_filter(
+            $this->schemas,
+            fn (Schema $schema) => $schema instanceof ExtensibleSchema && !$schema->isResettable()
+        );
+    }
+
     public function getSchemasNames(): array
     {
-        return array_keys($this->schemas);
+        return array_merge(array_keys($this->schemaBuilders), array_keys($this->schemas));
     }
 
     public function setMaxQueryDepth(int $maxQueryDepth): void
diff --git a/src/Resolver/AbstractResolver.php b/src/Resolver/AbstractResolver.php
index b0deb7a54..7d81d9c9d 100644
--- a/src/Resolver/AbstractResolver.php
+++ b/src/Resolver/AbstractResolver.php
@@ -4,21 +4,21 @@
 
 namespace Overblog\GraphQLBundle\Resolver;
 
+use Symfony\Contracts\Service\ResetInterface;
 use function array_keys;
 
-abstract class AbstractResolver implements FluentResolverInterface
+abstract class AbstractResolver implements FluentResolverInterface, ResetInterface
 {
+    private array $solutionsFactory = [];
     private array $solutions = [];
     private array $aliases = [];
     private array $solutionOptions = [];
-    private array $fullyLoadedSolutions = [];
 
     public function addSolution(string $id, callable $factory, array $aliases = [], array $options = []): self
     {
-        $this->fullyLoadedSolutions[$id] = false;
         $this->addAliases($id, $aliases);
 
-        $this->solutions[$id] = $factory;
+        $this->solutionsFactory[$id] = $factory;
         $this->solutionOptions[$id] = $options;
 
         return $this;
@@ -28,7 +28,7 @@ public function hasSolution(string $id): bool
     {
         $id = $this->resolveAlias($id);
 
-        return isset($this->solutions[$id]);
+        return isset($this->solutionsFactory[$id]);
     }
 
     /**
@@ -81,13 +81,12 @@ private function loadSolution(string $id)
             return null;
         }
 
-        if ($this->fullyLoadedSolutions[$id]) {
+        if (isset($this->solutions[$id])) {
             return $this->solutions[$id];
         } else {
-            $loader = $this->solutions[$id];
+            $loader = $this->solutionsFactory[$id];
             $this->solutions[$id] = $solution = $loader();
             $this->onLoadSolution($solution);
-            $this->fullyLoadedSolutions[$id] = true;
 
             return $solution;
         }
@@ -110,10 +109,15 @@ private function resolveAlias(string $alias): string
      */
     private function loadSolutions(): array
     {
-        foreach ($this->solutions as $name => &$solution) {
-            $solution = $this->loadSolution($name);
+        foreach (array_keys($this->solutionsFactory) as $name) {
+            $this->loadSolution($name);
         }
 
         return $this->solutions;
     }
+
+    public function reset(): void
+    {
+        $this->solutions = [];
+    }
 }
diff --git a/src/Resolver/TypeResolver.php b/src/Resolver/TypeResolver.php
index 26b9810a8..39fd87030 100644
--- a/src/Resolver/TypeResolver.php
+++ b/src/Resolver/TypeResolver.php
@@ -28,6 +28,11 @@ public function setCurrentSchemaName(?string $currentSchemaName): void
         $this->currentSchemaName = $currentSchemaName;
     }
 
+    public function getCurrentSchemaName(): ?string
+    {
+        return $this->currentSchemaName;
+    }
+
     public function setIgnoreUnresolvableException(bool $ignoreUnresolvableException): void
     {
         $this->ignoreUnresolvableException = $ignoreUnresolvableException;
@@ -82,4 +87,11 @@ protected function supportedSolutionClass(): ?string
     {
         return Type::class;
     }
+
+    public function reset(): void
+    {
+        parent::reset();
+
+        $this->cache = [];
+    }
 }
diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml
index 915b24e12..aabc71fa0 100644
--- a/src/Resources/config/services.yaml
+++ b/src/Resources/config/services.yaml
@@ -21,11 +21,15 @@ services:
         calls:
             - ["setMaxQueryComplexity", ["%overblog_graphql.query_max_complexity%"]]
             - ["setMaxQueryDepth", ["%overblog_graphql.query_max_depth%"]]
+        tags:
+            - {name: 'kernel.reset', 'method': "reset"}
 
     Overblog\GraphQLBundle\Definition\Builder\SchemaBuilder:
         arguments:
             - '@Overblog\GraphQLBundle\Resolver\TypeResolver'
             - false
+        tags:
+            - { name: 'kernel.reset', 'method': "reset" }
 
     Overblog\GraphQLBundle\Definition\Builder\TypeFactory:
         arguments:
@@ -37,6 +41,7 @@ services:
             - ['setDispatcher', ['@event_dispatcher']]
         tags:
             - { name: overblog_graphql.service, alias: typeResolver }
+            - {name: 'kernel.reset', 'method': "reset"}
 
     Overblog\GraphQLBundle\Transformer\ArgumentsTransformer:
         arguments: