diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/ExtractSubReactionNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/ExtractSubReactionNetwork.java
new file mode 100644
index 0000000000000000000000000000000000000000..64fab85fd2d439dce46cd638a3a379676eb9d405
--- /dev/null
+++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/ExtractSubReactionNetwork.java
@@ -0,0 +1,138 @@
+package fr.inrae.toulouse.metexplore.met4j_toolbox.networkAnalysis;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection;
+import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.KShortestPath;
+import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.ShortestPath;
+import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.SteinerTreeApprox;
+import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.weighting.DefaultWeightPolicy;
+import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.weighting.DegreeWeightPolicy;
+import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.weighting.WeightsFromFile;
+import fr.inrae.toulouse.metexplore.met4j_graph.core.BioPath;
+import fr.inrae.toulouse.metexplore.met4j_graph.core.GraphFactory;
+import fr.inrae.toulouse.metexplore.met4j_graph.core.WeightingPolicy;
+import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.CompoundGraph;
+import fr.inrae.toulouse.metexplore.met4j_graph.core.reaction.CompoundEdge;
+import fr.inrae.toulouse.metexplore.met4j_graph.core.reaction.ReactionGraph;
+import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.ReactionEdge;
+import fr.inrae.toulouse.metexplore.met4j_graph.io.Bionetwork2BioGraph;
+import fr.inrae.toulouse.metexplore.met4j_graph.io.ExportGraph;
+import fr.inrae.toulouse.metexplore.met4j_graph.io.NodeMapping;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.JsbmlReader;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException;
+import fr.inrae.toulouse.metexplore.met4j_mapping.Mapper;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.AbstractMet4jApplication;
+import org.kohsuke.args4j.Option;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+
+public class ExtractSubReactionNetwork extends AbstractMet4jApplication {
+
+    @Option(name = "-i", usage = "input SBML file", required = true)
+    public String inputPath = null;
+    @Option(name = "-s", usage = "input sources txt file", required = true)
+    public String sourcePath = null;
+    @Option(name = "-t", usage = "input targets txt file", required = true)
+    public String targetPath = null;
+    @Option(name = "-o", usage = "output gml file", required = true)
+    public String outputPath = null;
+    @Option(name = "-sc", aliases = {"--side"}, usage = "a file containing list of side compounds to ignore", required = true)
+    public String sideCompoundFile = null;
+
+    
+    @Option(name = "-cw", aliases = {"--customWeights"}, usage = "an optional file containing weights for reactions pairs")
+    public String weightFile = null;
+
+    @Option(name = "-k", usage = "Extract k-shortest paths", forbids = {"-st"})
+    public int k = 1;
+    @Option(name = "-st", aliases = {"--steinertree"}, usage = "Extract Steiner Tree", forbids = {"-k"})
+    public boolean st = false;
+
+
+    public void run() throws IOException, Met4jSbmlReaderException {
+        //import network
+        JsbmlReader reader = new JsbmlReader(this.inputPath, false);
+        BioNetwork network = reader.read();
+
+        //Graph processing: import side compounds
+        System.err.println("importing side compounds...");
+        Mapper<BioMetabolite> mapper = new Mapper<>(network,BioNetwork::getMetabolitesView).skipIfNotFound();
+        BioCollection<BioMetabolite> sideCpds = mapper.map(sideCompoundFile);
+        if(mapper.getNumberOfSkippedEntries()>0) System.err.println(mapper.getNumberOfSkippedEntries() + " side compounds not found in network.");
+        System.err.println(sideCpds.size() + " side compounds ignored during graph build.");
+
+        //get sources and targets
+        System.err.println("extracting sources and targets");
+        Mapper<BioReaction> rmapper = new Mapper<>(network,BioNetwork::getReactionsView).skipIfNotFound();
+        HashSet<BioReaction> sources = new HashSet<>(rmapper.map(sourcePath));
+        if(rmapper.getNumberOfSkippedEntries()>0) System.err.println(rmapper.getNumberOfSkippedEntries() + " source not found in network.");
+        HashSet<BioReaction> targets = new HashSet<>(rmapper.map(targetPath));
+        if(rmapper.getNumberOfSkippedEntries()>0) System.err.println(rmapper.getNumberOfSkippedEntries() + " target not found in network.");
+
+        //Create reaction graph
+        Bionetwork2BioGraph builder = new Bionetwork2BioGraph(network);
+        ReactionGraph graph = builder.getReactionGraph(sideCpds);
+
+        //Graph processing: set weights [optional]
+        WeightingPolicy<BioReaction, CompoundEdge, ReactionGraph> wp = new DefaultWeightPolicy<>();
+        if (weightFile != null) {
+            wp = new WeightsFromFile(weightFile, true);
+        }
+        wp.setWeight(graph);
+
+        //extract sub-network
+        GraphFactory<BioReaction, CompoundEdge, ReactionGraph> factory = new GraphFactory<>() {
+            @Override
+            public ReactionGraph createGraph() {
+                return new ReactionGraph();
+            }
+        };
+        ReactionGraph subnet;
+        if (st) {
+            SteinerTreeApprox<BioReaction, CompoundEdge, ReactionGraph> stComp = new SteinerTreeApprox<>(graph);
+            List<CompoundEdge> stEdges = stComp.getSteinerTreeList(sources, targets, (weightFile != null));
+            subnet = factory.createGraphFromEdgeList(stEdges);
+        } else if (k > 1) {
+            KShortestPath<BioReaction, CompoundEdge, ReactionGraph> kspComp = new KShortestPath<>(graph);
+            List<BioPath<BioReaction, CompoundEdge>> kspPath = kspComp.getKShortestPathsUnionList(sources, targets, k);
+            subnet = factory.createGraphFromPathList(kspPath);
+        } else {
+            ShortestPath<BioReaction, CompoundEdge, ReactionGraph> spComp = new ShortestPath<>(graph);
+            List<BioPath<BioReaction, CompoundEdge>> spPath = spComp.getShortestPathsUnionList(sources, targets);
+            subnet = factory.createGraphFromPathList(spPath);
+        }
+
+        //export sub-network
+        ExportGraph.toGmlWithAttributes(subnet, outputPath);
+
+    }
+
+    public static void main(String[] args) throws IOException, Met4jSbmlReaderException {
+        ExtractSubReactionNetwork app = new ExtractSubReactionNetwork();
+        app.parseArguments(args);
+        app.run();
+    }
+
+    @Override
+    public String getLabel() {
+        return this.getClass().getSimpleName();
+    }
+
+    @Override
+    public String getLongDescription() {
+        return this.getShortDescription() + "\n" +
+                "The subnetwork corresponds to part of the network that connects reactions from the first list to reactions from the second list.\n" +
+                "Sources and targets list can have elements in common. The connecting part can be defined as the union of shortest or k-shortest paths between sources and targets, " +
+                "or the Steiner tree connecting them. Contrary to compound graph, reaction graph often lacks weighting policy for edge relevance. In order to ensure appropriate " +
+                "network density, a list of side compounds to ignore for linking reactions must be provided. An optional edge weight file, if available, can also be used.";
+    }
+
+    @Override
+    public String getShortDescription() {
+        return "Create a subnetwork from a GSMN in SBML format, and two files containing lists of reactions of interests ids, one per row, plus one file of the same format containing side compounds ids.";
+    }
+}