Generating a non binary tree structure
Let's start from your code. The recursion can be implemented in a much clearer way if the method returns the collection of all child folders, instead of updating parent folder's ChildItems collection. In this case it could look as simple as

private IEnumerable&lt;Node&gt; GetChildFolderNodes(IRepository&lt;Folder&gt; folderRepo, int folderId)
{
    var childFolders = folderRepo.FindByExp(f =&gt; f.ParentFolderID == folderId).ToArray();

    return childFolders.Select(folder =&gt; new Node
    {
        Id = folder.FolderID,
        ParentId = folder.ParentFolderID,
        DisplayText = folder.FolderName,
        DefaultState = false,
        ChildItems = GetChildFolderNodes(folderRepo, folder.FolderID).ToList()
    });
}


There are a number of articles describing why a IRepository&lt;T&gt; is quite a bad idea when defined on top of ORM framework. Main reasons are leaked abstractions and abstraction on top of abstraction. And your example shows why - any optimization requires the knowledge of underlying implementation (Entity Framework).

Running this process in multiple threads may help, but will put additional load on the database server and thus is not scalable. Note that Entity Framework's DbContext is not thread-safe, so you cannot share the IRepository in multiple threads unless you spin up a new DbContext per request there (which I wouldn't recommend doing).

Assuming that you're using Entity Framework 6.0, FindByExp method returns IQueryable&lt;Folder&gt;, you can try asynchronous implementation of the data retrieval:

private async Task&lt;List&lt;Node&gt;&gt; GetChildFolderNodesAsync(Func&lt;IRepository&lt;Folder&gt;&gt; folderRepoFactory, int folderId)
{
    Folder[] childFolders;
    using (var folderRepo = folderRepoFactory())
    {
        childFolders = await folderRepo.FindByExp(f =&gt; f.ParentFolderID == folderId).ToArrayAsync();
    }

    return (await Task.WhenAll(childFolders.Select(async folder =&gt; new Node
    {
        Id = folder.FolderID,
        ParentId = folder.ParentFolderID,
        DisplayText = folder.FolderName,
        DefaultState = false,
        ChildItems = await GetChildFolderNodesAsync(folderRepoFactory, folder.FolderID)
    }))).ToList();
}


Note that in this case you would need to spin up a new DbContext per request (which I expressed as a repository factory).

And finally, assuming that this is a critical path in your application, the best way to optimize the code you're running is to reduce the number of round trips to database server, instead of trying to squeeze microseconds on a .NET layer.

For example, if your underlying DB engine is SQL Server, you can leverage the recursive CTE to load full folder hierarchy in one go. It can be optimized even further if CTE returns the depth level for folders, but I'll leave it for you as an exercise:

private List&lt;Node&gt; GetChildFolderNodesAsync(DbSet&lt;Folder&gt; folderSet, int folderId)
{
    var allFolders = folderSet.SqlQuery(@"WITH cte (FolderID, ParentFolderID, FolderName) AS
    (
        SELECT  FolderID, ParentFolderID, FolderName
        FROM    Folders
        WHERE   ParentFolderID = @p0
    UNION ALL
        SELECT  F.FolderID, F.ParentFolderID, F.FolderName
        FROM    Folders F
        JOIN    cte
        ON      F.ParentFolderID = cte.FolderID
    )
    SELECT  *
    FROM cte", folderId).AsNoTracking();

    //Converting all folders into nodes, but skipping the ChildItems property for now...
    var nodesByParent = allFolders
        .GroupBy(folder =&gt; folder.ParentFolderID)
        .ToDictionary(folders =&gt; folders.Key, folders =&gt; folders.Select(folder =&gt; new Node
        {
            Id = folder.FolderID,
            ParentId = folder.ParentFolderID,
            DisplayText = folder.FolderName,
            DefaultState = false,
        }).ToList());

    List&lt;Node&gt; childNodes;

    //Now that we have all nodes grouped by parent, we can look up and assign ChildItems for all nodes
    foreach (var node in nodesByParent.Values.SelectMany(nodes =&gt; nodes))
    {
        node.ChildItems = nodesByParent.TryGetValue(node.Id, out childNodes)
            ? childNodes
            : new List&lt;Node&gt;();
    }

    return nodesByParent.TryGetValue(folderId, out childNodes)
        ? childNodes
        : new List&lt;Node&gt;();
}